2012-03-06 205 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没有任何意义。我会重新考虑这个设计决定。