Socket通信中的 BeginReceive与EndReceive
BeginReceive 与endReceive 必须成对出现,如果BeginReceive没有及时调用endReceive,可能会出现数据被从buffer中读取二次,如果在下面这行代码下面加入别的代码
就会出现被处理二次的结果 如下
public void BeginReceive(SessionListner listner) { if (listner.State != TSessionState.Active) { return; } try { int bufferOffset = this.BufferManager.GetReceivevBufferOffset(m_bufferBlockIndex); WorkSocket.BeginReceive(this.BufferManager.ReceiveBuffer, bufferOffset, this.BufferManager.ReceiveBufferSize, SocketFlags.None, this.EndReceiveDatagram, listner); listner.Receive(); } catch (Exception err) // 读 Socket 异常,准备关闭该会话 { listner.DisconnectType = TDisconnectType.Exception; listner.State = TSessionState.Inactive;//这个客户状态不活动了 //说明发送端口被异常关闭了 this.OnSessionReceiveException(listner, err); } }
上面的 listner.Receive();处理缓存数据方法
然后再执行
private void EndReceiveDatagram(IAsyncResult iar) { SessionListner listner = (iar.AsyncState as SessionListner); if (listner.State != TSessionState.Active) { return; } try { int cr = WorkSocket.EndReceive(iar); Console.WriteLine(cr); if (cr == 0) { listner.DisconnectType = TDisconnectType.Normal; listner.State = TSessionState.Inactive; //被关闭了,需要及时关闭 } else { listner.LastSessionTime = DateTime.Now; this.BufferManager.RealReceiveSize = cr; this.BeginReceive(listner); } }
就出现被二次处理的问题,分析得出:1,在第一次读取完就处理缓冲数据,2同时进入了EndReceiveDatagram方法,再一次时进入BeginReceive方法 ,但没有处理完第一次缓存数据,就可能导致处理数据不正确。
需要改成:EndReceiveDatagram中处理数据
else { listner.LastSessionTime = DateTime.Now; this.BufferManager.RealReceiveSize = cr; listner.Receive(); this.BeginReceive(listner); }
总结:处理数据永远需要放到接收后处理,BeginReceive在永远不断的起线程,而endReceive在不断的帮它完成回收和结束工作。在Begin中下面放执行代码有可能有一定问题。也就是在没有end的时候,没有阻塞后,再操作共享变量有一定问题,所以begin与end同时操作共享对象或变量时时一定要end之后。无论socket还是一般的异步委托方法。