【准备】
游戏引擎:Unity3D - 5.4.1
脚本编辑器:Visual Studio 2012
脚本语言:C#
【前言】
亦泽将会开设Socket系列博文来记录自己学习Socket通讯知识的情况,并为大家粗浅的介绍Socket相关内容。关于这方面亦泽掌握的知识既不深也不多,毕竟不是专做网络这方面,但是了解相关的基础知识还是很有必要的,从微观来说,可以为以后做的小项目增光添彩,从长远来说,对宏观思维能力有一定的提高。
【理论】
Socket定义:
下述文字会有部分内容参考自百度百科,其余均为自己的理解,如果有较大偏差还请相关专业的读者给我留言。
从专业定义角度:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的每一端都称为一个Socket。建立网络通信连接时至少要一对Socket(即客户端的Socke与服务器的Socket)。Socket本质是API(应用程序接口)。
从通俗角度:Socket翻译为汉语为“孔,插座”,举个例子,一个插排我们可以想象它就是服务器,它有很多插口,每个插口就是一个Socket,有的插口用于给手机充电,有的插口用于给Pad充电,有的插口用于给电视机供电,那么手机Pad电视机这些就相当于不同的客户端(准确来说是不同的应用程序,因为“一个客户端”这样的词汇往往会使人联想到是一台客户的电脑,但是一台电脑上可以有许多的应用进程,每个与远程服务器有连接关系的都是一个Socket),连接服务器和客户端的两个端点都是Socket。
在对Socket有了基本的认识后,就要进入我们本次实战的主题——服务器与客户端的连接。
连接过程:
服务器监听——客户端请求——连接确认。
过程描述:
服务器会创建Socket实例,然后处于等待连接的状态也就是监听状态,当客户端的Socket指出服务器的IP和端口后,即可向服务器发出连接请求,服务器为请求连接的客户端创建一个Socket(此时服务器和客户端一般都需要单独开启一个线程来处理通信),完成双向连接,此时服务器可继续监听是否有客户端连接。
具体细节:
一,服务器部分
1、创建Socket实例,为其指定协议族,类型,以及协议。
我们这边通常使用的TCP/IP协议,是一种面向连接的、可靠的、面对字节流的传输方式,所以协议我们指定为TCP协议;协议族决定Socket的地址类型,我们这里采用Ipv4地址与端口号的组合;而且类型我们选择流(Stream)方式来完成,这是一种面向连接的方式。
2、对地址和端口号进行绑定。
我们可以打开cmd窗口输入ipconfig回车然后查看自己的网络IP是多少,然后端口号可以随便指定一个,端口号范围是(0~65535)建议指定为4位数以上(这样是避免端口号发生重复,端口号用于唯一标识当前电脑的某一应用进程,而有些端口号特别数值偏小的端口号已经被协议占用,比如80端口就是HTTP协议占用,而其他应用进程采用的端口号一般也是比较小的数字,所以我们自己学习时最好用四五位这样的端口号),利用IP和端口号的组合我们可以创建一个远程终结点,这个点唯一标识一个网络中的应用进程。然后我们使用Bind方法来绑定这个点来指定给服务器端的Socket。
3、启用监听。
可以使用Listen方法来开始监听,此时我们可以指定一个参数为最大链接数,控制服务器的负载。
4、等待客户端连接。
启动Accept方法,这个方法是一个阻塞方法,意思是如果没有客户端请求连接程序就会停留在这行代码,直到有客户端连接时才会执行下一行代码,这个方法具有Socket类的返回值,我们创建Socket实例来接收这个返回值,从而创建与客户端连接的Scoket端点。
二,客户端部分
1、与服务器部分第1步一致
2、创建远程终结点。
这一步在端口号和地址的部分与服务器部分一样。注意,这里创建的终结点的IP必须与服务器端一致,因为是客户端向服务器发起连接请求,客户端需要知道要连接的服务器终结点是什么才能发起请求。客户端不需要使用Bind方法绑定终结点。
3、发起连接。
使用Connect方法发起连接,参数为服务器的终结点。
【实践】
一.服务器:
打开Visual Studio,创建C#的控制台程序,创建好后如图所示。
添加如下代码(主要代码上方均有注释):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
namespace Socket_ArtCreateSpace
{
class Program
{
const string _ip =
"192.168.1.107";
const int _port =
7788;
static void Main(
string[] args)
{
Socket serverSocket =
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse(_ip);
IPEndPoint ipPoint =
new IPEndPoint(ipAddress, _port);
serverSocket.Bind(ipPoint);
serverSocket.Listen(
100);
Console.WriteLine(
"Server socket is running......");
Socket clientSocket = serverSocket.Accept();
Console.WriteLine(
"A client is connected!");
Console.ReadKey();
}
}
}
注:Socket需要添加两个命名空间的引用,已在代码中给出
运行程序,可以看到如图所示效果。
保持此窗口一直打开,即我们的服务器端是开启着。
二.客户端:
新建Unity工程,然后直接创建脚本Client,添加如下代码:
using UnityEngine;
using System.Collections;
using System.Net;
using System.Net.Sockets;
public class Client : MonoBehaviour {
Socket clientSocket;
const string _ip =
"192.168.1.107";
const int _port =
7788;
void Start () {
clientSocket =
new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ipAddress = IPAddress.Parse(_ip);
IPEndPoint ipPoint =
new IPEndPoint(ipAddress, _port);
clientSocket.Connect(ipPoint);
Debug.Log(
"Connect success!");
}
}
将此脚本场景中随便一个物体上,我这里挂到了摄像机上,运行游戏,同时观察服务器端和客户端,会发现服务器端和客户端打印如图所示,表明服务器与客户端连接成功。
【结语】
在Socket通讯中,连接虽然是最为基础的部分,但也是最重要的部分。连接功能不仅作为通讯的前提条件,也能直观的从连接功能中看出Socket应用进程间的通讯关系,以便在今后的网络相关开发中更好的理解主机间的逻辑关系。亦泽也是初学这部分,有喜欢这方面和相关专业的朋友可以联系亦泽,共同进步。最后,若文章有描述不够准确的地方还请大家多多包涵。
【GitHub】
https://github.com/Eazey/Socket_Connection.git
转载请注明原文地址: https://ju.6miu.com/read-662073.html