прерыватель разговора с сокетом

#sockets

#сокеты

Вопрос:

При чтении данных в сокете важно либо сохранить message terminator symbo l, либо добавить Packet size information в начале сообщения.

Если используется символ терминатора и отправляется двоичное сообщение, нет гарантии, что символ терминатора не появится в середине сообщения (если не используется какая-либо специальная кодировка).

С другой стороны, если прикреплена информация о размере. информация о размере не имеет знака, и если для нее используется один байт, ее нельзя использовать для передачи сообщений длиной более 256 байт. если используется целое число в 4 байта. даже не гарантируется, что 4 байта будут целыми. может прийти только 2 байта информации о размере, если предположить, что информация о размере поступила, он может использовать эти 2 байта, а остальные целочисленные данные будут отброшены. ожидание, пока в буфере чтения будут доступны 4 байта, может привести к бесконечному ожиданию, если в буфере доступно только 3 байта (например, если общий буфер составляет 7 байт или 4077 байт длиной).

здесь есть два возможных способа

  1. Разделитель sizeInfo

    читать до тех пор, пока разделитель не будет найден после того, как найден, читать до тех пор, пока не будут переданы sizeInfo байты

  2. сохраняйте unreadyBytes инициализированный в 4 после получения sizeInfo измените его соответствующим образом

какой из этих двух безопаснее использовать? Пожалуйста, критикуйте

Редактировать

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

Комментарии:

1. Ваш вопрос не имеет особого смысла. Пожалуйста, подумайте о том, чтобы полностью переписать его.

Ответ №1:

даже не гарантируется, что 4 байта будут целыми. может прийти только 2 байта информации о размере, если предположить, что информация о размере поступила, он может использовать эти 2 байта, а остальные целочисленные данные будут отброшены. ожидание, пока в буфере чтения будут доступны 4 байта, может привести к бесконечному ожиданию, если в буфере доступно только 3 байта (например, если общий буфер составляет 7 байт или 4077 байт длиной).

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

В любом случае, я предлагаю вам не использовать какой-либо разделительный фрагмент. Поместите заголовок в блоки данных, которые вы передаете, и используйте буфер для восстановления потока пакетов.

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

Вы можете определить базовую структуру для пакета:

 struct packet{
     uint32 id;
     char payload[MAX_PAYLOAD_SIZE];
};
  

Вы считываете данные из сокета, сохраняя их в буфере:

 struct packet buffer;
  

Затем вы можете считывать данные из сокета:
int n;
n = чтение (newsocket, amp;buffer, sizeof(uint32) MAX_PAYLOAD_SIZE);

read возвращает количество прочитанных байтов. Если вы прочитали именно пакет от отправителя, то n = id. В противном случае, возможно, вы читаете больше данных. отправитель отправил вам больше пакетов). Если вы получаете поток данных, разделенный на единицы (представленный структурами пакетов), тогда вы можете использовать массив пакетов для хранения всего полученного пакета и временный буфер для управления входящими фрагментами. Что-то вроде:

структурировать буфер пакетов[MAX_PACKET_STORED]; char temp_buffer[MAX_PAYLOAD_SIZE 4];

int n; n = чтение (newsocket, amp;buffer, sizeof(uint32) MAX_PAYLOAD_SIZE);

//здесь предположим, что получен пакет полезной нагрузки в 100 байт 32 бита длины 100 Байт // фрагментов следующего пакета. //затем:

 int first_pack_len, second_pack_len;

first_pack_len = *((uint32 *)amp;temp_buffer[0]); //retrieve packet length

memcpy(amp;packet_buffer[0], temp_buffer, first_pack_len   sizeof(uint32)) //store the first packet into the array

second_pack_data_available_in_buffer = n - (first_pack_len   sizeof(uint32)); //total bytes read minus length of the first packet read
second_pack_len = *((int *)amp;temp_buffer[first_pack_len   sizeof(uint32)]);
  

Я надеюсь, что выразился достаточно ясно. Но, возможно, я неправильно понимаю ваш вопрос.
Обратите внимание также, что если две взаимодействующие конечные системы могут иметь разные порядковые номера, поэтому лучше использовать функцию htonl / ntohl для длины при отправке / получении значения длины. Но это уже другая проблема)

Комментарии:

1. В этом и заключается проблема. как узнать, что данные заголовка поступили полностью.

2. @Neel Basu: заголовок должен иметь фиксированный размер. Если вы читаете меньше, это не будет завершено.

3. @Neel Basu: я завершил свой ответ, пытаясь объяснить это лучше. В любом случае, я не уверен, что это было ваше реальное сомнение. Проверьте это.