2012-03-06 246 views
1

我正在處理C#中的套接字編程。我需要構建一個客戶端應用程序,它使用給定的協議與服務器進行通信。異步套接字客戶端接收

我成功實現了異步發送方法,但是在實現接收算法時遇到了麻煩。同步接收方法工作正常。

首先,我需要不斷閱讀傳入的消息並對它們進行確認。爲了正確,每個收到的消息都必須有一個終結符(0x0c)

我構建了一個名爲MessageFlow的多線程類,其中包含三個線程:一個負責發送消息,另一個負責接收消息,第三負責處理解釋收到的消息並做一些事情。

用於接收線程的工作器功能看起來像這樣

private void ReadSocketWorker() 
{ 
    while (this.canRun) 
    { 
    xComClient.Receive(); 
    xComClient.receiveDone.WaitOne(); 
    Thread.Sleep(10); 
    } 
} 

XComClient是具有插座,所有的方法我的類來發送和接收消息。

public void Receive() 
{ 
    try 
    { 
     StateObject state = new StateObject(); 
     state.workSocket = socketClient; 
     socketClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); 
    } 
    catch (Exception e) 
    { 
     throw e; 
    } 
} 

private void ReceiveCallback(IAsyncResult ar) 
     { 
      try 
      { 
       StateObject state = (StateObject)ar.AsyncState; 
       Socket client = state.workSocket; 

       // Read data from the remote device. 
       int iReadBytes = client.EndReceive(ar); 

       if (iReadBytes > state.GetBufferSize()) 
       { 
        byte[] bytesReceived = new byte[iReadBytes]; 
        Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes); 
        state.responseList.Enqueue(bytesReceived); 
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
         new AsyncCallback(ReceiveCallback), state); 
       } 
       else 
       { 
        byte[] bytesReceived = new byte[iReadBytes]; 
        Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes); 
        state.responseList.Enqueue(bytesReceived); 
        BuildReceivedMessage(state); 
        receiveDone.Set(); 
       } 
      } 
      catch (Exception e) 
      { 
       throw e; 
      } 
     } 

public class StateObject 
{ 
    public Socket workSocket = null; 
    public const int BufferSize = 20480; 
    public byte[] buffer = new byte[BufferSize]; 

    public Queue<byte[]> responseList = new Queue<byte[]>(); 

    public int GetBufferSize() 
    { 
     return BufferSize; 
    } 
} 

我在做什麼錯?

回答

1

您的設計是同步和異步編程的混合。正確設計的異步類根本不需要使用任何線程,但讓.NET管理線程。

我真的很希望throw e;只是在這個例子中。由於它正在銷燬堆棧跟蹤(因此隱藏發生異常的地方)。你可以閱讀我的文章Don't catch that exception和我的其他文章標籤exceptions

,接收方法可以是這樣的:

void OnReceive(IAsyncResult ar) 
{ 
    AppendInternalReadBuffer(); 
    CheckInternalReadBufferForMessageAndProcessIt(); 
    ReadAgain(); 
} 

將從每客戶端的時間等待處理多個郵件阻塞服務器。如果你不想這樣做(這使事情變得複雜),你可以使用的CheckInternalReadBufferForMessageAndProcessIt

+0

謝謝。通過結合同步/異步方法,我完全搞砸了 – Francesco 2012-03-06 13:12:46

2

在線程中使用異步I/O沒有任何意義。我會重新考慮這個設計決定。