powered by simpleCommunicator - 2.0.53     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сокеты - несколько сообщений в одном коннекте
25 сообщений из 38, страница 1 из 2
Сокеты - несколько сообщений в одном коннекте
    #39276778
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Что-то я запутался в сокетах, требуется открыть соединение с сервером, отправить и получить оттуда несколько сообщений, закрыть коннект. В интернете написано что что-бы разделять сообщения надо к примеру вставлять header с длиной сообщения, и соответственно читать столько байтов, сколько указано в хэдере.
Однако в примерах которые я нашел, включая на мсдн'е никаких заголовков нет https://msdn.microsoft.com/en-us/library/kb5kfec7(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx и для синхронного и для асинхронного типа чтения.
И при этом моя тестовая программа тоже вроде как правильно работает с нижеследующим кодом:


Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
// Sends data to a connected Socket. 
int bytesSend = senderSock.Send(msgAll);

// Receives data from a bound Socket. 
int bytesRec = senderSock.Receive(bytes);

// Converts byte array to string 
String theMessageToReceive = Encoding.GetEncoding(selectedCodePage).GetString(bytes, 0, bytesRec);

// Continues to read the data till data isn't available 
while (senderSock.Available > 0)
{
   bytesRec = senderSock.Receive(bytes);
   theMessageToReceive += Encoding.GetEncoding(selectedCodePage).GetString(bytes, 0, bytesRec);
}




Так нужны все эти заголовки или нет?
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276789
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
stenfordТак нужны все эти заголовки или нет?
Нужны, но нет единого стандарта их оформления. В каждом случае выбирается какой-то вариант. Читай доки к своему серверу, там должно быть написано.
TCP-соединение это поток байт, а не блоков данных (сообщений), поэтому тут нельзя ожидать что отправленное сообщение придет целиком, за раз может прийти как полсообщения, так и полтора или два. Для этого и надо знать размер, чтобы понять где конец каждого сообщения.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276790
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код у тебя кривой
Код: c#
1.
while (senderSock.Available > 0)


тут выйдешь из цикла не дочитав. Т.к. Available это сколько байт в буфере сокета, но не факт что там все отправленное, запросто может оказаться что там только часть, а остальное еще в дороге.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276794
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TНужны, но нет единого стандарта их оформления. В каждом случае выбирается какой-то вариант. Читай доки к своему серверу, там должно быть написано.
TCP-соединение это поток байт, а не блоков данных (сообщений), поэтому тут нельзя ожидать что отправленное сообщение придет целиком, за раз может прийти как полсообщения, так и полтора или два. Для этого и надо знать размер, чтобы понять где конец каждого сообщения.

я не могу что-то нагуглить примеров как надо правильно читать с хэдерами, и приведенном мною примере у майкрософта тоже нет никаких хэдеров. У них получается неверный пример?

while (senderSock.Available > 0) - это наверно вообще можно убрать т.к. насколько я понял senderSock.Receive(bytes) считает все в синхронном виде и в потоке больше ничего не останется. Если-же поток может содержать неполные сообщения, то непонятно как его надо модофицировать что-бы считывать до конца
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276810
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Примеры MS упрощенные. Там один запрос и сообщение несколько десятков байт. Тут можно быть уверенным что за раз прилетит целиком.

По хорошему делается так:
Отправка:
4 байта размер сообщения (BitConverter в помощь)
само сообщение

Прием:
читаем 4 байта, получаем размер
читаем в цикле кусками пока не получим полностью сообщение нужного размера.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276815
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Забыл упомянуть что данного алгоритма должны придерживаться обе стороны, и сервер и клиент. Если у тебя сервер стороннее приложение, то там должно быть описано как именно передается размер. Вполне возможно по другому, например жестко зашито что одно сообщение 100 байт, тогда размер не надо передавать. Это называется протокол обмена, соглашение по форматам, которые должны придерживаться обе стороны. Стандартов тут нет, решает разработчик как ему удобнее. Самый простой способ как выше написал, но бывают другие варианты.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276828
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Готовых примеров на C# нет, на С писал подобное. Просто совет чтоб надежно работало: исходи из того что может прийти сразу несколько сообщений за раз. Никто не запрещает отправить сразу два запроса, и потом ждать два ответа. С отправкой проблем нет, все проблемы в чтении.
Например: прочитал размер 10000 байт, затем пришло 6000, а потом еще 6000. Вот тут твой код должен прочитать сначала первые 6000, а потом ждать оставшиеся 4000 и добавить их в конец, т.к. с 4001 это уже начало следующего сообщения.

И перекодировку Encoding.GetEncoding() можно делать только после приема сообщения целиком, т.к. в UTF-8 некоторые символы (русские буквы например) кодируются двумя байтами и нет гарантии что в полученном куске последний символ целиком, а не половина.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276833
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Кроме заголовка могут использваться разнообразные разделители
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276848
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TГотовых примеров на C# нет, на С писал подобное. Просто совет чтоб надежно работало: исходи из того что может прийти сразу несколько сообщений за раз. Никто не запрещает отправить сразу два запроса, и потом ждать два ответа. С отправкой проблем нет, все проблемы в чтении.
Например: прочитал размер 10000 байт, затем пришло 6000, а потом еще 6000. Вот тут твой код должен прочитать сначала первые 6000, а потом ждать оставшиеся 4000 и добавить их в конец, т.к. с 4001 это уже начало следующего сообщения.

И перекодировку Encoding.GetEncoding() можно делать только после приема сообщения целиком, т.к. в UTF-8 некоторые символы (русские буквы например) кодируются двумя байтами и нет гарантии что в полученном куске последний символ целиком, а не половина.

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

int bytesRec = senderSock.Receive(bytes);

если сообщение там не полное - как его дочитать-то? Скажем хэдер говорит что длина 1000 байтов, я указанным выше методом считал 800. Надо дочитать 200 байтов, как это сделать?
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276853
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Указать в Socket.Receive()
Примерно так:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
int need = 1000;
int pos = 0;
var bytes = new byte[need];
while(need > 0) {
   int recv = senderSock.Receive(bytes, pos, need, SocketFlags.None);
   need -= recv;
   pos += recv;
}
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276866
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Почитал хэлп, не надо циклов.
https://msdn.microsoft.com/ru-ru/library/8s4y8aff(v=vs.110).aspx Эта перегрузка требуется только для обеспечения приемного буфера.По умолчанию смещение буфера равно 0, размер установлен по умолчанию равным параметру буфера, а значение SocketFlags задано по умолчанию равным None.

...
Если используется объект Socket, ориентированный на установление соединения, метод Receive будет выполнять чтение доступного объема данных, вплоть до максимального размера буфера.Если удаленный узел отключает соединение Socket с методом Shutdown и получены все доступные данные, метод Receive будет немедленно завершен и вернет нулевое число байтов.
Если правильно понимаю, но Receive(bytes); будет тупо висеть и ждать данных пока полностью не заполнится массив bytes

Тогда можно просто
Код: c#
1.
2.
3.
var bytes = new byte[need];
int recv = senderSock.Receive(bytes);
if(recv != need) ... ошибка
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276968
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
хм, так ведь если размер указан в хэдере, а хэдер это часть сообщения которое нельзя прочитать пока Receive(bytes) не вернет. Что-то здесь не так, если мы должны прочитать сначала хэдер, то указать размер массива до момента начала чтения не получится никак
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39276978
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
stenfordхм, так ведь если размер указан в хэдере, а хэдер это часть сообщения которое нельзя прочитать пока Receive(bytes) не вернет. Что-то здесь не так, если мы должны прочитать сначала хэдер, то указать размер массива до момента начала чтения не получится никак
Размер как именно указан? Т.е. размер размера какой?
Если например фиксировано 4 байта, то сначала читай ровно 4 байта, а потом из прочитанного извлекай размер. Если переменная длина и разделитель, то читай побайтно, пока разделитель не прочитаешь.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277020
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
это как, прочитать поток 2 раза?

Код: c#
1.
2.
3.
4.
5.
var bytesSize = new byte[4];
int size = ConvertToInt(senderSock.Receive(bytesSize ));

var bytesAllMessage = new byte[size];
int recv = senderSock.Receive(bytesAllMessage );



т.е. первое чтение только считает 4 байта, а второе уже само сообщение нужной длины?
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277032
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а кстати такой момент, ведь на данный момент тестовое приложение работает с произвольным размером массива (1024 байта), и результаты дает правильные. Так может действительно проще просто указывать размер массива заведомо больше чем самое больше сообщение, ну скажем 5000 байтов, и все будет работать безо всяких чтений хэдеров? Сейчас-же работает с массивом байтов который больше чем тестовое сообщение
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277035
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Именно так. Только проверки размера прочитанного добавь. Там не всегда исключение, по хэлпу может выпасть вернув 0 если та сторона закроет соединение.

Еще раз TCP-соединение это поток байт, а не блоков данных (сообщений), поэтому какими порциями прочитаешь, такие сообщения и получатся. Все что гарантирует TCP это то что отправленное будет принято в той же последовательности. Если понятнее надо - считай что размер это часть сообщения, а отдельное сообщение содержащее размер следующего за ним сообщения.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277036
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Опечатка, так правильно
Dima TЕсли понятнее надо - считай что размер это не часть сообщения, а отдельное сообщение содержащее размер следующего за ним сообщения.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277039
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
stenfordТак может действительно проще просто указывать размер массива заведомо больше чем самое больше сообщение, ну скажем 5000 байтов, и все будет работать безо всяких чтений хэдеров?
ХЗ как оно у тебя работает, согласно хэлпу должно висеть и ждать пока буфер полностью не заполнится или сервер не закроет соединение.
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277052
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ок, спасибо, поэксперементирую еще
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277432
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
думаю в русском переводе косяк, в оригинальной английской версии сказано следующее:

If you are using a connection-oriented Socket, the Receive method will read as much data as is available , up to the size of the buffer.

https://msdn.microsoft.com/en-us/library/8s4y8aff(v=vs.110).aspx

это означает что метод не будет висеть пока буфер не заполнится, а считает сколько доступно, и вернет результат. Совершенно непонятно каким образом он узнает что мессадж закончился. Может все-таки эти сокеты умные, и сами определяют конец сообщения и начало следующего?

На тестовом сервере выполняется следующий метод

int bytesSend = handler.EndSend(ar);

Т.е. возможно конец сообщения как-то помечается. С другой стороны на реальном сервере используется операционка IBM и как они там отправляют сообщения совершенно неизвестно, известно только что включен хэдер с длиной
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277452
Фотография Изопропил
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
stenford,

Ну нету у tcp сокета никаких сообщений и искуственного интеллекта
Хоть об стену убеся - нету
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277459
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
stenfordдумаю в русском переводе косяк, в оригинальной английской версии сказано следующее:

If you are using a connection-oriented Socket, the Receive method will read as much data as is available , up to the size of the buffer.

https://msdn.microsoft.com/en-us/library/8s4y8aff(v=vs.110).aspx

это означает что метод не будет висеть пока буфер не заполнится, а считает сколько доступно, и вернет результат.
Если так то использовать вариант с циклом 19429924

Затестить просто, дай больше буфер, не заполнит, значит так как ты пишешь. Оно именно так на уровне API ОС, ждет пока не пришло что-нибудь, поэтому приходится всегда циклы делать, подумал что в С# это порешали.

stenfordСовершенно непонятно каким образом он узнает что мессадж закончился. Может все-таки эти сокеты умные, и сами определяют конец сообщения и начало следующего?
Сокеты не умные, там все просто: сообщение, которое ты даешь на отправку дописывается в конец буфера отправки (его создает ОС для каждого сокета), затем это разбивается на IP-пакеты (~1460 байт) и пакеты отправляются в сеть. По приходу содержимое пакетов дописывается в буфер приема и читающий софт читает из буфера. .Available это и есть сколько байт на текущий момент в буфере. При блокирующем чтении ожидающий разблокировывается как только хоть что-то упадет в буфер.

Если задержки между отправками большие и данных мало, то создается иллюзия что "сокеты умные", т.к. получатель успевает обработать содержимое каждого пакета отдельно. Но если в буфер приема успеют прийти два пакета (от разных сообщений), то ты прочитаешь их вместе, или например большое сообщение уйдет тремя пакетами, третий немного отстанет, то ты прочитаешь сначала содержимое первых двух, а следующим чтением остальное. Поэтому без размера тут никак. Другой вариант - использовать разделители.

В твоем случае, раз у тебя работа по принципу запрос-ответ, два ответа вместе ты никак не получишь, т.к. второй запрос после чтения ответа на первый, но получить ответ двумя чтениями это вполне возможная ситуация (см. выше про несколько IP-пакетов и последний отстал).
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277462
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dima TЕсли так то использовать вариант с циклом 19429924

Затестить просто, дай больше буфер, не заполнит, значит так как ты пишешь. Оно именно так на уровне API ОС, ждет пока не пришло что-нибудь, поэтому приходится всегда циклы делать, подумал что в С# это порешали.


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

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
 // Sends data to a connected Socket. 
  int bytesSend = senderSock.Send(msgAll);

  // Receives data from a bound Socket. 
  byte[] messageHeaderBytes = new byte[2];

  // Get header bytes first
  int bytesHeader = senderSock.Receive(messageHeaderBytes);
  int messageLength = HexToInt(ByteArrayToHexString(messageHeaderBytes));

  // Now recieve message itself
  byte[] messageBytes = new byte[messageLength];
  int bytesRec = 0; 

  while (bytesRec < messageLength)
  {
      bytesRec = senderSock.Receive(messageBytes, bytesRec, messageLength, SocketFlags.None);                
   }

   // Converts byte array to string 
   String theMessageToReceive = Encoding.GetEncoding(selectedCodePage).GetString(messageBytes, 0, bytesRec);
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277463
stenford
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
правда протестить как в цикле крутится наверно неполучится раз он все сообщение сразу получает, но вроде должно теперь работать
...
Рейтинг: 0 / 0
Сокеты - несколько сообщений в одном коннекте
    #39277467
Dima T
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ерунду написал, тут зациклится если придет в три чтения.
Код: c#
1.
2.
3.
4.
  while (bytesRec < messageLength)
  {
      bytesRec = senderSock.Receive(messageBytes, bytesRec, messageLength, SocketFlags.None);                
   }


Смотри мой пример, там три переменных:
need - размер ожидаемого сообщения
pos - смещение куда читать очередную порцию
recv - сколько прочиталось за раз
...
Рейтинг: 0 / 0
25 сообщений из 38, страница 1 из 2
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сокеты - несколько сообщений в одном коннекте
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]