Ограничен ли полученный поток из сокета одной командой send? - PullRequest
2 голосов
/ 15 июля 2010

В настоящее время я работаю с многопоточным приложением, в котором я получаю данные, используя следующий (упрощенный) код:

private void BeginReceiveCallback(IAsyncResult ar)
{
bytesReceived = this.Socket.EndReceive(ar);
byte[] receivedData = new byte[bytesReceived];
Array.Copy(buffer, receivedData, bytesReceived);

long protocolLength = BitConverter.ToInt64(receivedData, 0);
string protocol = Encoding.ASCII.GetString(receivedData, 8, (int)protocolLength);
IList<object> sentObjects = 
ParseObjectsFromNetworkStream(receivedData, 8 + protocolLength);

InvokeDataReceived(protocol, sentObjects);
}

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

Мой вопрос заключается в том, какие данные я могу ожидать хранить в этом буфере.Может ли он содержать данные двух разных операций отправки со стороны клиента?В этом случае, я полагаю, мне придется придумать протокол, который сможет различать «сообщения» данных, отправленные со стороны клиента.Простой подход состоит в том, чтобы соответственно начинать и заканчивать каждый поток определенным (уникальным) байтом.Есть ли общий подход к разделению сообщений?Кроме того, я предполагаю, что это означает, что одного вызова приема может быть недостаточно для получения всех данных от клиента, что означает, что мне придется зацикливаться, пока не будет найден конечный байт?

Ответы [ 3 ]

3 голосов
/ 15 июля 2010

Соединения сокетов TCP / IP состоят из двух независимых потоков: одного входящего и одного исходящего.

Это одна из ключевых концепций TCP / IP, которая часто пропускается.С точки зрения приложения, TCP / IP не работает с пакетами;он работает с потоками!

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

Например, одна сторона может отправить 5 байтов, а затем отправить еще 5 байтов.Принимающая сторона может получать две партии по 5 байтов, или одну за раз, или все 10 за одно чтение ...

Чтобы разбить входящий поток байтов на сообщения, вам необходимо создать кадры сообщения.Обычно используется одно из двух решений.Одним из предложенных вами является решение delimiter , в котором байты SOT / EOT используются для обозначения границ сообщения.Другое (которое я предпочитаю) - это решение длина префикса , в котором длина сообщения добавляется к самому сообщению.

Более подробное обсуждение в моем блоге вместе с образцом кода для префикса длины .

1 голос
/ 15 июля 2010

вы правы, поток, полученный сокетом, может быть либо усеченным (принудительное отключение), либо, как вы видели, он может содержать дополнительные данные из другой операции отправки.

Вы можете поэкспериментировать с настройками сокета, чтобы указать немедленную отправку (nagle? Я думаю, это называется)

Благодаря работе, которую я проделал с TCP, у меня есть протокол связи, который используется для двоичных данных, и другой протокол, используемый для ascii. Когда я отправляю двоичные данные, у меня есть известные данные, с которых все коммуникации должны начинаться (BlockType (2 байта) BlockLength (4 байта) данных (нБайт))

Затем принимающая сторона знает, что нужно прочитать 6 байтов, чтобы определить тип и длину. Если я получаю менее 6 байт, попробуйте, пока я не сделаю и не буферизую предыдущие значения и т. Д., После того, как установленный размер станет известным, считайте, пока вы не прочитаете из данных байты BlockLength (буферизация по необходимости).

Если у вас отсоединено гнездо, вам нужно иметь дело с возобновлением или перезапуском и т. Д.

Если я работаю с данными ascii, я использую уникальный метод обтекания для блока передаваемых данных (~~~ start ~~~) .... DATA .... (~~~ end ~~~) чем просто буферизовать содержимое в строителе строк или аналогичном, пока вы не нажмете (~~~ end ~~~), а затем продолжите свои операции.

Надеюсь, это поможет.

1 голос
/ 15 июля 2010

При использовании TCP / IP данные обычно считаются потоком. Вы можете получить столько, сколько отправлено (и вам может понадобиться снова «получить», чтобы получить все, что было отправлено). Распространенная ситуация состоит в том, что у двух конечных точек будет своего рода диалог вперед-назад. Это не похоже на ситуацию, которую вы описываете. Простая обработка того, что делает ваше приложение, заключается в отправке данных длиной в первые несколько байтов (например, 4-байтовое целое число). Принимающая сторона получит 4 байта, чтобы найти ожидаемую длину, а затем получит эту точную сумму.

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