共计 2459 个字符,预计需要花费 7 分钟才能阅读完成。
前言:本篇文章主题 Tcp 连贯 Socket 套接字相干内容,对根底局部、优化补充局部做了阐明,最终目标是让阅读者看完本篇文章后能写一个功能完善的网络框架。
首先明确一下网络连接的根底模块有哪些
[根底局部 2]数据接管
客户端 Socket 连贯后开始接收数据,客户端接收数据的形式个别有两种
[数据接管第一种]
开线程,为何开线程:数据接管不须要和 Mono 交互,仅仅是对 byte[]数据的操作,开线程提高效率,上面是代码示例
这个没什么好说的,四个重载接口区别不大
// 数据初始化
uint ReceiveMaxByteCount;
byte[] bufferTemp = new byte[ReceiveMaxByteCount];
pubvoid void Connect(string _ip,int _port)
{
SocketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(_ip);
IPEndPoint point = new IPEndPoint(ip, _port);
SocketClient.NoDelay = true;
SocketClient.Connect(point);
}
[根底局部 2]数据接管
客户端 Socket 连贯后开始接收数据,客户端接收数据的形式个别有两种
[数据接管第一种]
开线程,为何开线程:数据接管不须要和 Mono 交互,仅仅是对 byte[]数据的操作,开线程提高效率,上面是代码示例
pubvoid void Connect(string _ip,int _port)
{SocketClient = new Socket()
//...........
// 这是第一种形式,开线程接管
Thread c_thread = new Thread(Received);
c_thread.IsBackground = true;
c_thread.Start();}
void Received()
{while (true)
{
try
{int len = _SocketClient.Receive(bufferTemp); //len 理论接管到的无效字节数
if (len <= 0)
{
// 异样解决
break;
}
// 把收到的字节解析或者塞入接管缓存池中
}
catch {}}
}
[数据接管第二种]
简略粗犷的写在 Update 里,如果是框架则应该有 tick 接管和发送缓存池的机制,这里是根底局部,只介绍外围代码
void Update()
{ProcessReceive()
}
void ProcessReceive()
{
uint recLen = 0;
if(client.Connected)
//maxLen 代表最大接管长度,如果有缓存池,接管长度不能超过缓存池残余量的长度
recLen = (uint)client.Receive(bufferTemp,maxLen, SocketFlags.None);
// 有池则入池,没池间接解析 bufferTemp,数据长度为 recLen
}
[根底局部 3]数据发送
void Send (Socket client, Byte[] buff, uint nLen, SocketFlags flags = SocketFlags.None)
{
try
{
// 提醒:sendLen 代表向 tcp 底层缓冲区塞了多少个字节,并不是向服务器发送胜利了多少个字节
uint sendLen = client.Send(buff, (int)nLen, flags);
}
catch (SocketException e)
{}}
[根底局部 4]: 断开连接
void Close (Socket ClientSocket)
{
try
{ClientSocket.Shutdown(SocketShutdown.Both);
ClientSocket.Close();}
catch (SocketException e)
{//LogSystem.Error(e.ToString());
}
}
Socket 根底局部外的优化
[补充优化 1]发送、接管缓存池
咱们能够把发送缓存池和接管缓存池都封装成一个 class,未来数据发送和接管的重任就落到了它俩身上,输入叫 SocketOutputPool, 输出叫 SocketInputPool
[补充优化 1 - 发送缓存池]
发送缓存池是干嘛的?基本原理就是保护一个 Byte 数组。
当下层业务有数据向服务器发送时,会调用 NetMgr 的 send 函数,send 函数再调用 SocketOutputPool 的 Write 函数向 Byte 数组中写入该数据。
缓存池的数据适合发送,发送多少?当 Write 函数写入数据后,该当记录一下以后数据长度,int 变量 m_PoolTail 记录尾部长度,上文有过对发送机会的形容,一般来说会在 Update 中调用发送函数
public const uint DEFAULT_SOCKET_OUTPUT_BUFFER_SIZE = 1024 * 80;// 缓存最大长度
int m_Tail = 0; // 缓存池以后长度
byte[] m_Buffer = new Byte[DEFAULT_SOCKET_OUTPUT_BUFFER_SIZE];
void TickSend()
{
// 再次提醒:SendLen 不是向服务器发送的长度,而是往 Tcp 发送缓冲区塞了多少数据
int SendLen = Socket.Send(m_Buffer,m_PoolTail, flag);
// 发送完结后,须要从池中把发送过得数据剔除
}
3、数据发送和数据接管能够写两个缓存池
注意事项:
1、Tcp 是否须要缓存池,可设置 bool 变量 Nodelay
2:socket.Send()办法的返回变量 int 值示意该 send 向 tcp 发送缓冲区塞了多少个字节,并不是向服务器发送胜利了多少个字节,
3:如果呈现发包失败,tcp 底层会主动重发,tcp 的底层有发送胜利回复机制,另一端收到音讯包后会回复一个确认包
图片起源:http://www.pizei.com/ 页游