我们知道两个进程如果需要进行通讯最基本的一个前提是有唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程。
能够唯一标示网络中的进程后,它们就可以利用socket进行通信了,什么是socket呢?我们经常把socket翻译为套接字,socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。
三次握手:
第一次握手:客户端尝试连接服务器,向服务器发送syn包,syn=j,客户端进入SYN_SEND状态等待服务器确认
第二次握手:服务器接收客户端syn包并确认(ack=j+1),同时向客户端发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态
第三次握手:第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手
服务器socket与客户端socket建立连接的部分其实就是大名鼎鼎的三次握手
Socket
using UnityEngine;
using System.Collections;
using System.Net;//网络
using System.Net.Sockets;//套接字
using System.Text;//文本
//我的Socket委托
public delegate void AlbertReceiveCallBack(string content);
public class AlbertSocketManager
{
#region 服务器端
//声明一个服务器端的套接字
Socket serverSocket;
//声明一个服务器端的委托
AlbertReceiveCallBack serverCallBack;
//声明一个byte缓存
byte[] serverBuffer = new byte[1024];
public void InitServer(AlbertReceiveCallBack rcb)
{
// 传入委托对象
serverCallBack = rcb;
//初始化服务器端的套接字(1)
serverSocket = new Socket(AddressFamily.InterNetwork,/*IPV4协议*/
SocketType.Stream, /*双向读写流**/
ProtocolType.Tcp/*TCP协议*/);
//实例一个网络端点,传入地址和端口
IPEndPoint serverEP = new IPEndPoint(IPAddress.Any, 23456);
//绑定网络端点(2)
serverSocket.Bind(serverEP);
//设置监听的最大数量(3)
serverSocket.Listen(10);
//异步接受客户端的连接(CallBack)(4)
serverSocket.BeginAccept(new System.AsyncCallback(ServerAccept), serverSocket);
//发送一个消息表示服务器已经创建
serverCallBack("Server Has Init");
}
private void ServerAccept(System.IAsyncResult ar)
{
//接收结果状态(5接收数据)
serverSocket = ar.AsyncState as Socket;
//接收结果
Socket workingSocket = serverSocket.EndAccept(ar);
//开始异步接收消息
workingSocket.BeginReceive(serverBuffer/*消息缓存*/,
0/*接收消息的偏移量*/,
serverBuffer.Length/*设置接收字节数*/,
SocketFlags.None/*Socket标志位*/,
new System.AsyncCallback(ServerRecive)/*接收回调*/,
workingSocket/*最后的状态*/);
//继续接收客户端的请求
workingSocket.BeginAccept(new System.AsyncCallback(ServerAccept), workingSocket);
}
private void ServerRecive(System.IAsyncResult ar)
{
//获取正在工作的Socket对象(用来接收数据)
Socket workingSocket = ar.AsyncState as Socket;
//接收到的数据字节数
int byteCount = 0;
//接收到的数据字符串
string content = "";
try
{
//尝试结束异步接收的消息
byteCount = workingSocket.EndReceive(ar);
}
catch (SocketException ex)
{
//如果接收失败,返回详细异常
serverCallBack(ex.ToString());
}
if (byteCount > 0)
{
//转换byte数组为字符串(支持中文)
content = UTF8Encoding.UTF8.GetString(serverBuffer);//字符编码
}
//发送接收到的消息
serverCallBack(content);
//继续接收消息
workingSocket.BeginReceive(serverBuffer/*消息缓存*/,
0/*接收消息的偏移量*/,
serverBuffer.Length/*设置接收字节数*/,
SocketFlags.None/*Socket标志位*/,
new System.AsyncCallback(ServerRecive)/*接收回调*/,
workingSocket/*最后的状态*/);
}
#endregion
#region 客户端 //声明客户端的套接字 Socket clientSocket; //声明客户端的委托对象 AlbertReceiveCallBack clientReceiveCallBack; //声明客户端的缓存1KB byte[] clientBuffer = new byte[1024]; ////// 实例化客户端方法 /// /// IP地址 /// 端口 /// 委托对象 public void InitClient(string ip, int port, AlbertReceiveCallBack rcb) { //接收客户端的委托对象 clientReceiveCallBack = rcb; //实例客户端的Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //实例化一个客户端的网络端点(把IP和端口传进来) IPEndPoint clientEP = new IPEndPoint(IPAddress.Parse(ip), port); //连接服务器 clientSocket.Connect(clientEP); clientSocket.BeginReceive(clientBuffer, 0, clientBuffer.Length, SocketFlags.None, new System.AsyncCallback(ClientReceive), clientSocket); } private void ClientReceive(System.IAsyncResult ar) { //获取一个客户端正在接收数据的Socket对象 Socket workingSocket = ar.AsyncState as Socket; int byteCount = 0; string content = ""; try { //结束接收数据,完成存储 byteCount = workingSocket.EndReceive(ar); } catch (SocketException ex) { //如果接收消息异常,发送异常消息 clientReceiveCallBack(ex.ToString()); } if (byteCount > 0) { //转换已经接收到的Byte数据为字符串 content = UTF8Encoding.UTF8.GetString(clientBuffer); } //发送数据 clientReceiveCallBack(content); //接收下一波数据 workingSocket.BeginReceive(clientBuffer, 0, clientBuffer.Length, SocketFlags.None, new System.AsyncCallback(ClientReceive), clientSocket); } ////// 客户端发送数据方法 /// /// 消息内容 public void ClientSendMessage(string msg) { if (msg != "") { //将要发送的字符串消息转换成byte数组 clientBuffer = UTF8Encoding.UTF8.GetBytes(msg); } clientSocket.BeginSend(clientBuffer, 0, clientBuffer.Length, SocketFlags.None, new System.AsyncCallback(SendMsg), clientSocket); } //客户端发送消息的回调函数 private void SendMsg(System.IAsyncResult ar) { Socket workingSocket = ar.AsyncState as Socket; workingSocket.EndSend(ar); } #endregion }
服务器端:
using UnityEngine;
using System.Collections;
public class ServerSocketDemo : MonoBehaviour {
private AlbertSocketManager albertSocketManager;
string serverContent;
void Awake()
{
albertSocketManager = new AlbertSocketManager();
//执行初始化服务器方法,传入委托函数
albertSocketManager.InitServer(ShowMsg);
}
///
/// Shows the message委托函数
///
/// Message
void ShowMsg(string msg)
{
serverContent = msg;
}
void OnGUI()
{
GUILayout.Label(serverContent);
}
}
using UnityEngine;
using System.Collections;
public class ClientSocketDemo : MonoBehaviour
{
private AlbertSocketManager albertSocketManager;
private string clientContent="";
private string needSendText="";
void Awake()
{
albertSocketManager = new AlbertSocketManager();
albertSocketManager.InitClient("127.0.0.1", 23456, (string msg) =>
{
clientContent = msg;
});
}
void OnGUI()
{
needSendText = GUILayout.TextField(needSendText);
if (GUILayout.Button("点击发送消息"))
{
if (needSendText != "")
{
albertSocketManager.ClientSendMessage(needSendText);
}
}
}
}