C# 使用Tcp和异步发送接收消息

C# 使用Tcp和异步发送接收消息,c#,asynchronous,tcp,buffer,C#,Asynchronous,Tcp,Buffer,我有一个代码(假设是一个简单的聊天应用程序),我使用Tcp和sync。但由于异步方式更好,尽管设置起来更难,所以我决定将方式从同步改为异步。但是现在我在使用异步时遇到了一些问题 缓冲区大小:我知道我们需要考虑有限的字节大小才能从对等体中获得字节。我读了很多文章,但我的问题没有得到解决,我有一个非常简单但毫无价值的方法来处理这个问题,在每条消息的末尾放一个字符;然后,接收者可以理解消息何时被完全接收。但我还有另一个问题,这使我无法进一步执行这种方法,而这又给我带来了另一个问题 让我用以下代码来解释

我有一个代码(假设是一个简单的聊天应用程序),我使用Tcp和sync。但由于异步方式更好,尽管设置起来更难,所以我决定将方式从同步改为异步。但是现在我在使用异步时遇到了一些问题

  • 缓冲区大小:我知道我们需要考虑有限的字节大小才能从对等体中获得字节。我读了很多文章,但我的问题没有得到解决,我有一个非常简单但毫无价值的方法来处理这个问题,在每条消息的末尾放一个字符;然后,接收者可以理解消息何时被完全接收。但我还有另一个问题,这使我无法进一步执行这种方法,而这又给我带来了另一个问题 让我用以下代码来解释我的问题:

    public void Send(byte[] message, Socket connection)
    {
        connection.BeginSend(message, 
                             0, 
                             message.Length, 
                             SocketFlags.None, 
                             new AsyncCallback(OnSend), 
                             connection);
    }
    
    在OnSend方法中,我只使用connection.EndSend(result)其中result是IAsyncResult。但当我像下面的代码一样两次调用Send方法时,OnReceive callback将把它们作为一条消息接收

    Send(Encoding.Unicode.GetBytes("Hello"));
    Send(Encoding.Unicode.GetBytes("Bye"));
    
    我的OnReceiveMethod将使用控制台.WriteLine(消息)其中message是从对等方接收的字符串。并且使用同步方式的输出必须是

    你好

    再见

    但在异步方式中,我将它作为一条消息而不是两条消息接收,所以它被打印出来

    海洛拜

    诚挚的,
    Peyman Mortazavi

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

    使用同步调用,您可以保证在发送第二条消息之前,第一条消息已完全发送。但是,使用异步方法,您只需将这两条消息添加到传出队列中,等待发送。如果你恰好在正确的时间点击它,它可能会将它们作为两条单独的消息发送,但由于你将它们添加得如此之快,它很可能会同时发送这两条消息。如果您将TCP/IP套接字通信视为一个正在进行的数据流,那么您的情况会好得多。您需要以一种可以确定消息开始和结束位置的方式格式化消息。当您通过套接字接收数据时,应不断将接收到的消息添加到缓冲区,直到(根据数据的格式)确定您已接收到完整的消息。您不应该依赖于从套接字读取的每一条消息都是一条完整的消息。您应该预料到它可能只是一条部分消息,甚至是多条消息。

    我必须说,我并不同意简单地切换到同步套接字来解决这个问题。更好的方法是使用
    队列
    (例如),在调用发送时将消息放入队列

    然后让异步套接字从这个队列中取出数据包,并在当前数据包发送完毕后发送下一个数据包,直到队列为空


    然后,在队列中再次出现消息之前,您可以选择不再次调用BeginSend。

    我必须说,我并不同意简单地切换到同步套接字来解决这个问题。更好的方法是使用
    队列
    (例如),在调用发送时将消息放入队列

    然后让异步套接字从这个队列中取出数据包,并在当前数据包发送完毕后发送下一个数据包,直到队列为空


    然后,在队列中再次出现消息之前,您可以选择不再次调用BeginSend。

    好的,现在我在Send方法处等待10毫秒,虽然时间很短,但可以解决问题。在自定义格式中,我可以理解消息的开始和结束时间。现在,我在Send方法中等待10毫秒,虽然时间很短,但可以解决问题。在自定义格式中,我可以理解消息的开始和结束时间。