Правильная техника для отправки нескольких фрагментов данных произвольной длины через TCP-сокет - PullRequest
2 голосов
/ 09 ноября 2011

Мне любопытно, как правильно отправить несколько кусков данных произвольной длины по сокету в C. Например, если нужно было отправить «имя пользователя» произвольной длины, «субъект» произвольной длины и«сообщение» произвольной длины, каким будет правильный процесс их отправки.Кроме того, данные, которые я пытаюсь отправить, могут не обязательно заканчиваться нулем, поэтому я не верю, что смогу правильно собрать их, основываясь только на нулевых байтах.

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

Ответы [ 3 ]

2 голосов
/ 09 ноября 2011

Ваше предложение является одним из способов решения проблемы. Это не «подвержено ошибкам», если сокет использует надежный транспорт, такой как TCP, так как сетевой уровень гарантирует, что данные будут доставлены не поврежденными и в правильном порядке. Другой способ сделать это - отправить структуры фиксированного размера, чтобы получатель всегда читал X байтов и знал, что получил полное сообщение. Другой - использовать терминатор поля, либо NUL (как вы предлагаете), либо символ новой строки; это то, что делают многие интернет-протоколы (например, HTTP, FTP). Еще один заключается в использовании метода сериализации (как предполагает другой ответ). Все зависит от того, какие данные вы планируете отправлять, и насколько должны быть переносимы данные между различными типами систем.

2 голосов
/ 09 ноября 2011

Вы хотите прочитать о сериализации. Несколько ссылок, которые могут быть полезны:

http://en.wikipedia.org/wiki/Serialization

http://en.wikipedia.org/wiki/External_Data_Representation

http://en.wikipedia.org/wiki/Protocol_buffers

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

1 голос
/ 09 ноября 2011

Во избежание усложнения ваших процедур отправки / получения, поскольку ваши структуры данных становятся более сложными, я рекомендую разбить проблему на отдельные шаги:

  1. Написать подпрограммы, которые могут создаватьи отправить произвольный буфер из N байтов по TCP-соединению.(Это может включать отправку префикса длиной 4 байта, а затем отправку N байтов, как вы описали).Возможно, вы также захотите включить 4-байтовый заголовок кода типа, который получатель может использовать, чтобы легко определить, какие из ваших структур данных должны представлять полученные байты.

  2. Написать подпрограммукоторый преобразует (ваша любимая структура данных) в серию из N байтов, которые хранятся в оперативной памяти.Затем напишите связанную подпрограмму, которая преобразует последовательность из N байтов, хранящихся в ОЗУ, обратно (ваша любимая структура данных).

  3. Повторите шаг (2) для любых других структур данных, которые вы хотитеотправить по проводу.Обратите внимание, что, если у вас есть несколько типов данных, поле кода типа, упомянутое в (1), облегчит для получателя знать, какую процедуру обратного преобразования вызывать после того, как он полностью получит байтовый буфер.

После того как вы сделали выше, вы можете использовать свой универсальный код send / receive-byte-buffers из (1) для переноса любой из ваших структур данных из (2), и таким образом вы нене нужно писать отдельный код отправки / получения для каждой структуры данных, что является большим выигрышем.

Обратите внимание, что если вы беспокоитесь о переносимости, вам необходимо обязательно преобразовать любое многобайтовое целое число или число с плавающей запятойзначения, которые вы хотите отправить в порядке с прямым порядком байтов (или порядке с прямым порядком байтов, не имеет значения, если вы последовательны), прежде чем отправлять их, а затем преобразовывать их обратно в исходный порядок байтов на получателе после их получения (но прежде чем использовать их ни для чего).(Вам также нужно избегать искушения просто использовать memcpy () в структурах C в байтовом буфере, поскольку разные платформы и даже разные версии компиляторов могут по-разному распределять структуры C в памяти, что приведет к катастрофическим результатам, есливаш отправитель и получатель не используют один и тот же исполняемый файл)

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