TCP-сервер неправильно читает сообщения фиксированного размера - PullRequest
2 голосов
/ 09 марта 2012

Я отправляю данные датчика с устройства Android на сервер TCP в C #.Клиент Android отправляет данные в виде фрагментов фиксированного размера 32 байта.

На сервере я читаю данные, ожидая, что они будут поступать в полных пакетах, но поскольку TCP является потоковым протоколом, некоторые сообщения поступают на сервер, разделенныйдве части.Я знаю это, потому что я могу смотреть его с помощью программного обеспечения под названием SocketSniff.

Проблема в том, что я не знаю, как справиться с этим на моем сервере.

Все примеры, которые я нашел, используют NetworkStream.Read(), в этом методе я должен передать массив байтов для хранения прочитанных данных, смещение и количество байтов для чтения.Этот массив байтов должен иметь известный размер, в моем случае 32.

Я не знаю реального размера сообщения, которое пришло на мой сервер, но это может быть одна из следующих ситуаций.

  • Если размер полученных данных составляет 32 байта, все в порядке.

  • Если размер полученных данных превышает 32 байта, я думаю, что я теряю данные.

  • Если размер полученных данных меньшечем 32 байта, скажем, 20 байтов, эти байты хранятся в моем массиве, а последние 12 байтов массива остаются со значением ноль.Поскольку я действительно получаю некоторые нули, нет способа узнать размер, который я действительно получил, поэтому я не могу объединить его с оставшимися данными, которые должны появиться в следующем чтении.

Мой код, который обрабатывает получение, следующий:

    int buffer = 32;
    ...
    private void HandleClientComm(object client)
    {
        TcpClient tcpClient = (TcpClient)client;
        NetworkStream clientStream = tcpClient.GetStream();

        byte[] message = new byte[buffer];
        int bytesRead;

        while (true)
        {
            bytesRead = 0;

            try
            {
                bytesRead = clientStream.Read(message, 0, message.Length);
            }
            catch
            {
                break;
            }

            if (bytesRead == 0)
            {
                // Connection closed
                break;
            }

            SensorData sensorData = ProcessTcpPacket(message);
        }
        tcpClient.Close();
    }

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

1 Ответ

6 голосов
/ 10 марта 2012

Ну, да, у вас есть переменная bytesRead - она ​​содержит количество байтов, прочитанных из потока.Вы прочитаете самое большее сообщение. Длинные байты, но вы можете прочитать меньше.

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

Что вам нужно сделать, это добавить еще один цикл в цикле, например:

int messageRead = 0;

while(messageRead < message.Length)
{ 
    int bytesRead = clientStream.Read(message, messageRead, message.Length - messageRead);
    messageRead += bytesRead;
    if(bytesRead==0)
        return;   // The socket was closed
}
// Here you have a full message
...