C# Socket BeginReceive/EndReceive 捕获多条消息

标签 c# sockets

问题:

当我做这样的事情时:

for (int i = 0; i < 100; i++)
{
    SendMessage( sometSocket, i.ToString());
    Thread.Sleep(250); // works with this, doesn't work without
}

无论有没有 sleep ,服务器都会记录单独消息的发送。然而,如果没有 sleep ,客户端最终会在单个 OnDataReceived 中收到多条消息,因此客户端将收到如下消息:

0, 1、 2、 34, 5、 678, 9 ....

服务器发送代码:

private void SendMessage(Socket socket, string message)
{
    logger.Info("SendMessage: Preparing to send message:" + message);            

    byte[] byteData = Encoding.ASCII.GetBytes(message);

    if (socket == null) return;
    if (!socket.Connected) return;

    logger.Info("SendMessage: Sending message to non " +
                "null and connected socket with ip:" + socket.RemoteEndPoint);

    // Record this message so unit testing can very this works.

    socket.Send(byteData);
}

客户端接收码:

private void OnDataReceived(IAsyncResult asyn)
{
    logger.Info("OnDataReceived: Data received.");

    try
    {
        SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
        int iRx = theSockId.Socket.EndReceive(asyn);
        char[] chars = new char[iRx + 1];
        System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
        int charLen = d.GetChars(theSockId.DataBuffer, 0, iRx, chars, 0);
        System.String szData = new System.String(chars);

        logger.Info("OnDataReceived: Received message:" + szData);

        InvokeMessageReceived(new SocketMessageEventArgs(szData));

        WaitForData();  // .....  

套接字数据包:

public class SocketPacket
{
    private Socket _socket;
    private readonly int _clientNumber;
    private byte[] _dataBuffer = new byte[1024]; ....

我的直觉是它与缓冲区大小有关,或者它只是在我们收到多条消息的 OnDataReceived 和 EndReceive 之间。

更新:事实证明,当我将 Thread.Sleep 放在 OnDataReceived 的开头时,它会收到每条消息。唯一的解决方案是将我的消息包装在一个长度前缀和一个表示结束的字符串中吗?

最佳答案

这是预期的行为。TCP 套接字表示线性字节流,不是一系列分隔明确的“数据包”。您不能假设您收到的数据的分块方式与发送时的方式相同。

请注意,这有两个后果:

  1. 两条消息可能会合并到一个回调调用中。 (你注意到了这个。)
  2. 单个消息可能会(在任何时候)拆分为两个单独的回调调用。

您的代码必须能够处理这两种情况,否则就会出现错误。

关于C# Socket BeginReceive/EndReceive 捕获多条消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3504654/

相关文章:

c# - 使用 Entity Framework 和 linq 从查询子集中获取最大日期时间(数据库列)?

c# - 反转颠倒位图数据的最佳方法

java - 如何在java中获取UDP数据包发送者的本地IP地址

multithreading - 国际象棋游戏: how to design the server

mysql - 无法连接到本地mysql服务器

c# - Oracle DataReader 不返回任何行

c# - 在不删除列或将其大小调整为零的情况下隐藏详细信息 View 中的 Windows 窗体 ListView 列

c# - 在客户端之间发送消息(Socket UDP)

c# - 连接两个套接字的问题

c# - 无法将类型 '.List<AnonymousType#1>' 隐式转换为 '.List<WebApplication2.Customer>'