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還是一般的異步委托方法。