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

时间:2019-01-12 14:55:36

标签: c# .net sockets tcp

我有一些Python代码,用于从相机捕获图像并将其发送到C#服务器。

从客户端发送消息时,我会在数据之前加上消息大小,以便我知道要从套接字服务器端提取多少数据。

在大多数情况下,它似乎运行良好,但有时-消息似乎并非以消息大小开头。

我不确定为什么会这样,但是我不知道如何处理。

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#

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);
}

消息缓冲区应如下所示:

enter image description here

良好运行:

enter image description here

在糟糕的情况下:

enter image description here

enter image description here

1 个答案:

答案 0 :(得分:1)

问题似乎出在此代码上:

string simple = returnSimpleObject(complex);


        public class SerializeData
        {
             public string[] EventData { get; set; }
        }

        private static string returnSimpleObject(string Json)
        {
            JObject jobject = JObject.Parse(Json);

            JToken tEventData = jobject.SelectToken("EventData");
            SerializeData myEvent = tEventData.ToObject<SerializeData>();

            JToken tchanges = jobject.SelectToken("EventData.ChangeSet.Change.changes");
            myEvent.EventData = tchanges.ToObject<string[]>();


            JsonSerializer serializer = new JsonSerializer();
            StringWriter strWrite = new StringWriter();
            JsonWriter myWriter = new JsonTextWriter(strWrite);
            serializer.Serialize(myWriter, myEvent);
            return strWrite.ToString();

        }

handler.Receive(tempBuffer, 0, StateObject.messageChunkSize, 0); messageBuffer.AddRange(tempBuffer); 返回实际读入Socket.Receive()中的字节数。您需要保存该值,然后使用它将正确的字节数复制到tempBuffer

messageBuffer