Как мне убедиться, что я получаю сообщение целиком, если оно не помещается в буфер в TCP? - PullRequest
0 голосов
/ 04 мая 2020

Я недавно начал работать с TCP в C#. Сейчас я нахожусь в точке, где я хочу, чтобы клиент получил данные, отправленные сервером.

Я знаю, что у клиента нет гарантии на получение всех данных одновременно. Если размер отправляемых данных больше размера буфера на стороне клиента, то данные будут отправлены по частям. Итак, мой вопрос: как я могу сохранить все полученные данные в байтовом массиве, а затем преобразовать их в реальное сообщение, когда все получено?

Я установил размер буфера в 1, чтобы я мог Посмотрите, что происходит, когда все отправленные данные не помещаются в буфер. Вот мои методы, в которых я вызываю stream.BeginRead() в Client.cs:

// Deliberately setting the buffer size to 1, to simulate what happens when the message doesn't fit in the buffer.
int bufferSize = 1;
byte[] receiveBuffer;

private void ConnectCallback(IAsyncResult result)
{
    client.EndConnect(result);

    Console.WriteLine("Connected to server.");

    stream = client.GetStream();

    // At this point, the client is connected, and we're expecting a message: "Welcome!"
    receiveBuffer = new byte[bufferSize];
    stream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, new AsyncCallback(ReadCallback), stream);
}

private void ReadCallback(IAsyncResult result)
{
    int bytesLength = stream.EndRead(result);

    // Should be "Welcome!". But of course it's "W", because the bufferSize is 1.
    string message = Encoding.UTF8.GetString(receiveBuffer, 0, bytesLength);

    Console.WriteLine("Received message: {0}", receivedMessage);

    // Reset the buffer and begin reading a new message, which will be "e".
    // However, I want the whole message ("Welcome!") in one byte array.
    receiveBuffer = new byte[bufferSize];
    stream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, ReadCallback, null);
}

Это вывод при отправке сообщения «Добро пожаловать!»:

Connected to server.
Received message: W
Received message: e
Received message: l
Received message: c
Received message: o
Received message: m
Received message: e
Received message: !

Должен ли я временно сохранять данные до тех пор, пока не будет получено все сообщение, а затем преобразовать их в строку?

Последующий вопрос: что делать, если два сообщения отправляются близко друг к другу, например, Welcome!, а затем What's your name? Как тогда различить guish два сообщения?

Ответы [ 2 ]

1 голос
/ 04 мая 2020

Должен ли я временно сохранить данные до получения всего сообщения, а затем преобразовать их в строку?

Да, точно.

Подписаться Вопрос: Что делать, если 2 сообщения отправляются близко друг к другу, например, Добро пожаловать! а потом как тебя зовут? Как мне тогда различить guish два сообщения?

Общий подход состоит в том, чтобы отправить длину сообщения до самого сообщения. Таким образом, принимающая сторона будет знать, когда она получит полный пакет.

0 голосов
/ 08 мая 2020

Как 500 - Внутренняя ошибка сервера уже указана, вы используете для нее буфер. Вот пример кода: Получение:

while (true) //you should use a bool variable here to stop this on disconnect.
                {
                    byte[] bytes;

                    bytes = ReadNBytes(ns, 4);
                    //read out the length field we know is there, because the server always sends it.
                    int msgLenth = BitConverter.ToInt32(bytes, 0);
                    bytes = ReadNBytes(ns, msgLenth);
                    //working with the buffer...
                    if (bytes.Length > 0)
                    {
                        try
                        {
                            //do stuff here. bytes contains your complete message.
                        }
                        catch (Exception e) { Log(e.Message); }                            
                    }
                }


public static byte[] ReadNBytes(NetworkStream stream, int n)
    {
        byte[] buffer = new byte[n];
        try
        {
            int bytesRead = 0;

            int chunk;
            while (bytesRead < n)
            {
                chunk = stream.Read(buffer, (int)bytesRead, buffer.Length - (int)bytesRead);
                if (chunk == 0)
                {
                    // error out
                    Log("Unexpected disconnect");
                    stream.Close();
                }
                bytesRead += chunk;
            }
        }
        catch (Exception e) { Log(e.Message); }

        return buffer;
    }

Чтобы отправить материал, используйте что-нибудь вроде этого:

public static void SendObject(NetworkStream ns, byte[] data)
    {
        byte[] lengthBuffer = BitConverter.GetBytes(data.Length);
        ns.Write(lengthBuffer, 0, lengthBuffer.Length);
        ns.Write(data, 0, data.Length);
    }

Я надеюсь, что это помогло!

...