TCP-сервер C # получает два сообщения, отправленных клиентом Python одновременно - PullRequest
2 голосов
/ 14 марта 2019

Я пытаюсь получить несколько сообщений, отправленных TCP-клиентом Python на сервер C #. Я получаю данные, но все сразу, и я не хочу, чтобы это произошло. Я попытался установить размер буфера сервера равным размеру байта [], который я отправляю, но это не сработало ( source ). Любые идеи, как я могу решить эту проблему?

Код отправки клиента:

import socket


def send_to_remote(sock, data):

data_bytes = bytearray()
data_bytes.extend(map(ord, data)) # appending the array with string converted to bytes

bytes_length = len(data_bytes) # length of the array that I am sending

sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, bytes_length) #   setting the buffer size to the array length

print(bytes_length)

sock.send(data_bytes) # sending the data

Сервер, получающий код:

 public static string ReadData(TcpClient connection)
    {
        StringBuilder receivedDataStr = new StringBuilder();
        NetworkStream connectionStream = connection.GetStream();

        if (connectionStream.CanRead)
        {
            byte[] connectionBuffer = new byte[connection.ReceiveBufferSize];

            Console.WriteLine(">> Reading from NODE");

            int bytesRead = 0;

            bytesRead = connectionStream.Read(connectionBuffer, 0, 1024);
            receivedDataStr.Append(Encoding.ASCII.GetString(connectionBuffer, 0, bytesRead));

            Console.WriteLine(">> " + connection.ReceiveBufferSize);

            return receivedDataStr.ToString();
        }
        else
        {
            Console.WriteLine(">> Can't read from network stream");
            return "none-read";
        }
    }

EDIT:

Что я делаю, это:

send_to_remote(socekt, "msg1")
send_to_remote(socekt, "msg1")

А потом:

string msg1 = ReadData(client);
string msg2 = ReadData(client);

Я получаю буферный массив 106200.

Результат:

"msg1 (then new line) msg2"
"" (string msg2 is waiting for data)

Заранее спасибо !!

1 Ответ

1 голос
/ 14 марта 2019

TCP - это протокол stream , а не протокол packet . абсолютно не гарантируется , что вы собираетесь получать данные в тех же точных фрагментах, в которых они были отправлены - все, что гарантировано, это то, что вы получите байты в правильном порядке (или ошибка, или тайм-аут и т. д.). Вы можете получить каждый байт отдельно или 14 сообщений одновременно. Или что-то промежуточное, включая половину сообщения за один прием, а другую половину - за следующий. В случае Unicode (и т. Д.) Это также означает, что один символ может быть разделен на несколько приемов.

Любой протокол мульти-сообщений, основанный на TCP, должен включать в себя какое-то обрамление , то есть какой-то способ узнать, где начинается и заканчивается каждое отдельное сообщение. Поскольку вы используете текстовый протокол, наиболее распространенным вариантом является разделение логических сообщений с помощью CR, LF или CR + LF, а затем ваша задача - буферизовать данные до тех пор, пока у вас не появится полное сообщение - путем поиска конец строки. Для полноты: в случае бинарных протоколов обычно используется полезная нагрузка с префиксом длины с каким-то заголовком, который указывает объем данных в полезной нагрузке, тогда вам просто нужно проанализировать заголовок, определить длину и создать буфер до есть столько данных.

В простых приложениях с текстовым протоколом и без проблем с масштабируемостью может быть возможно использовать StreamReader (поверх NetworkStream), чтобы выполнить эту часть за вас, а затем просто использовать ReadLine или ReadLineAsync. Обратите внимание, однако, что это было бы плохой идеей на «реальных» серверах (особенно ReadLine) - вы не хотите, чтобы вредоносный или просто глючный клиент блокировал поток навсегда только потому, что он отправил несколько символов без конец строки , а потом больше ничего не отправлял ... никогда. Конечно, на серьезном сервере вы бы не использовали поток для каждого клиента в любом случае .

...