【问题标题】:Asynchronous socket client receive异步套接字客户端接收
【发布时间】:2012-03-06 11:05:14
【问题描述】:

我正在处理 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;
    }
}

我做错了什么?

【问题讨论】:

    标签: c# sockets asyncsocket


    【解决方案1】:

    在没有其他事情可做的线程中使用异步 I/O 确实没有任何意义。我会重新考虑这个设计决定。

    【讨论】:

      【解决方案2】:

      您的设计是同步和异步编程的混合体。设计合理的异步类根本不需要使用任何线程,而是让 .NET 管理线程。

      我真的希望throw e; 只是在示例中。因为它正在破坏堆栈跟踪(因此隐藏了异常发生的位置)。你可以阅读我的文章Don't catch that exception和我的其他文章标记exceptions

      接收方法可能如下所示:

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

      这将阻止服务器在每个客户端一次处理多个消息。如果您不想这样做(这会使事情变得复杂),您可以在CheckInternalReadBufferForMessageAndProcessIt 中使用ThreadPool

      【讨论】:

      • 谢谢。结合同步/异步方法,我绝对搞砸了
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多