简体   繁体   English

从套接字接收消息时确定可变消息长度的可靠方法

[英]Reliable way to determine variable message length when receiving from socket

I have some Python code for capturing images from a camera and sending them to a C# server. 我有一些Python代码,用于从相机捕获图像并将其发送到C#服务器。

When sending the messages from the client- I precede the data with the message size so I know how much data to pull from the socket server-side. 从客户端发送消息时,我会在数据之前加上消息大小,这样我就知道要从套接字服务器端提取多少数据。

It seems to work well most of the time, but occasionally - the message doesn't appear to start with the message size. 在大多数情况下,它似乎运行良好,但有时-消息似乎并非以消息大小开头。

I'm not sure why this is happening but I can't figure out how to deal with it. 我不确定为什么会这样,但是我不知道如何处理。

Python code: Python代码:

while True:
    send_message("SEND_FRAME_DATA_HERE")

def send_message(message):

    message_size = len(message.encode())

    print (f"Message: {message_size} - {message}")

    my_socket.sendall(struct.pack(">L", message_size) + message.encode())

C# C#

private const int MESSAGE_CHUNK_SIZE = 4096;
private const int MESSAGE_PREFIX_SIZE = 4;

private void _receiveMessage(IAsyncResult ar)
{
    StateObject state = (StateObject)ar.AsyncState;
    Socket handler = state.workSocket;
    List<byte> messageBuffer = new List<byte>();
    byte[] tempBuffer = new byte[MESSAGE_CHUNK_SIZE];

    try
    {
        handler.EndReceive(ar);
        messageBuffer.AddRange(state.messageBuffer);

        while (true)
        {
            while (messageBuffer.Count < MESSAGE_PREFIX_SIZE)
            {
                handler.Receive(tempBuffer, 0, MESSAGE_CHUNK_SIZE, 0);
                messageBuffer.AddRange(tempBuffer);
            }

            int messageLength = _getMessageLength(messageBuffer);

            // Occasionally the four bytes determining message length
            // are read from what appears to be mid message
            if (messageLength > 20)
            {
                Console.Write("halp");
            }

            messageBuffer = messageBuffer.Skip(MESSAGE_PREFIX_SIZE).ToList();

            while (messageBuffer.Count < messageLength)
            {
                handler.Receive(tempBuffer, 0, StateObject.messageChunkSize, 0);
                messageBuffer.AddRange(tempBuffer);
            }

            var wholeMessage = messageBuffer.Take(messageLength).ToList();
            var messageString = Encoding.Default.GetString(wholeMessage.ToArray());

            Console.WriteLine(messageString);

            messageBuffer = messageBuffer.Skip(messageLength).ToList();
        }
    }
    catch (SocketException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

private int _getMessageLength(List<byte> message)
{
    byte[] bytes = { message[3], message[2], message[1], message[0] };
    return BitConverter.ToInt32(bytes, 0);
}

The message buffer should look something like this: 消息缓冲区应如下所示:

在此处输入图片说明

On a good run: 在良好的运行中:

在此处输入图片说明

On a bad run: 在糟糕的情况下:

在此处输入图片说明

在此处输入图片说明

The problem appears to be with this code: 问题似乎与以下代码有关:

handler.Receive(tempBuffer, 0, StateObject.messageChunkSize, 0);
messageBuffer.AddRange(tempBuffer);

Socket.Receive() returns the number of bytes actually read into the tempBuffer . Socket.Receive()返回实际读入tempBuffer的字节数。 You need to save that value, and then use it to copy the correct number of bytes to messageBuffer . 您需要保存该值,然后使用它将正确的字节数复制到messageBuffer

int bytesRead = handler.Receive(tempBuffer, 0, StateObject.messageChunkSize, 0);
messageBuffer.AddRange(tempBuffer.Take(bytesRead));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM