使用带有Async的Tcp发出接收消息

时间:2012-05-17 13:13:37

标签: c# asynchronous tcp buffer

我有一个代码(假设一个简单的聊天应用程序),我使用Tcp同步。但由于Async方式更好,虽然设置起来比较困难,但我决定改变从同步到异步的方式。但现在我在使用异步时遇到了一些问题。

  1. 缓冲区大小:我知道我们需要考虑有限大小的字节来从对等方获取字节。我阅读了很多文章,但我的问题没有解决,我有一个非常简单但毫无价值的方法来处理这个问题,在每条信息的末尾添加一个字符;然后接收者可以理解何时完全接收消息。但是我还有另外一个问题阻止我对这个问题进行进一步的解决。
  2. 让我通过以下代码解释我的问题:

    public void Send(byte[] message, Socket connection)
    {
        connection.BeginSend(message, 
                             0, 
                             message.Length, 
                             SocketFlags.None, 
                             new AsyncCallback(OnSend), 
                             connection);
    }
    

    在OnSend方法中,我只使用 connection.EndSend(result),其中结果是IAsyncResult。但是当我然后像下面的代码一样调用Send方法两次时,OnReceive回调将接收它们作为单个消息。

    Send(Encoding.Unicode.GetBytes("Hello"));
    Send(Encoding.Unicode.GetBytes("Bye"));
    

    我的OnReceiveMethod将使用 Console.WriteLine(message); 其中message是从peer收到的字符串。并且使用同步方式的输出必须是

    你好

    再见

    但是以异步方式我收到它作为一条消息而不是两条消息,因此它被打印

    HelloBye

    真诚的,你的, Peyman Mortazavi

2 个答案:

答案 0 :(得分:4)

我必须说我不同意简单地切换到同步套接字来克服这个问题。一个更好的方法是使用Queue<string>(例如),在调用send时将消息放入其中。

然后让你的异步套接字从这个队列中出队,并在当前队列完成发送时发送下一个,直到队列为空。

然后您可以选择不再次调用BeginSend,直到队列中再次显示消息。

答案 1 :(得分:2)

使用同步呼叫,您可以保证在发送第二条消息之前完全发送第一条消息。但是,使用异步方法,您只需将两条消息添加到传出队列,等待发送。如果您碰巧在正确的时间点击它,它可能会将它们作为两个单独的消息发送,但由于您将它们添加得如此之快,因此很可能将两者一起发送。如果您认为TCP / IP套接字通信是一个持续的数据流,那么您将会好得多。您需要以可以确定其开始和结束位置的方式格式化消息。当您通过套接字接收数据时,应该继续将收到的消息添加到缓冲区,直到您确定(基于数据的格式)您已收到完整的消息。您不应该依赖套接字中的每个读取作为单个完整的消息。您应该期望它可能只是部分消息甚至是多条消息。