Отправка структуры через TCP (C-программирование) - PullRequest
2 голосов
/ 14 ноября 2009

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

Я выполнил все подключения и т. Д., И мне уже удалось отправить строку через:

send(socket, string, string_size, 0);

Итак, возможно ли отправить структуру вместо строки через send ()? Могу ли я просто заменить свой буфер на сервере на пустую структуру того же типа и перейти?

Ответы [ 7 ]

4 голосов
/ 14 ноября 2009

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

Прагматично, я предполагаю, что ваш клиент и сервер - это один и тот же тип компьютера, и то, что вы предлагаете, будет работать, однако вы должны знать, что, как правило, это не так, и поэтому такие стандарты, как CORBA была изобретена, или почему люди используют некоторые общие представления, такие как XML.

2 голосов
/ 14 ноября 2009

Вы можете, если клиент и сервер выстроили структуру одинаково, то есть все поля имеют одинаковый размер с одинаковым заполнением. Например, если у вас есть long в вашей структуре, это может быть 32 бита на одном компьютере и 64 бита на другом, и в этом случае структура не будет принята правильно.

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

Для большинства клиент-серверных приложений это означает, что ответ заключается в том, что вы не можете сделать это вообще. Что вы на самом деле делаете, так это определяете сообщение с точки зрения количества отправленных байтов, порядка, что они означают и так далее. Затем на каждом конце вы делаете что-то платформо-зависимое, чтобы гарантировать, что структура, которую вы используете, имеет в точности нужный макет. Тем не менее, вам, возможно, придется выполнить некоторую замену байтов, если вы отправляете целочисленные члены структуры little-endian, а затем хотите, чтобы ваш код выполнялся на машине с прямым порядком байтов. Существуют форматы обмена данными, такие как XML, json и буферы протокола Google, так что вам не нужно делать эту сложную работу.

[Edit: также помните, конечно, что некоторые члены структуры никогда не могут быть отправлены по проводам. Например, если в вашей структуре есть указатель, то адрес относится к памяти на отправляющем компьютере и бесполезен на принимающей стороне. Извиняюсь, если это уже очевидно для вас, но, конечно, это не очевидно для всех, когда они только начинают с C].

1 голос
/ 14 ноября 2009

Можно, но нужно знать 2 важные вещи.

  1. Программы на обоих концах должны быть ABI совместимыми. Обычно они выполняются, если оба конца работают на одной и той же архитектуре процессора, в одной ОС, скомпилированы с одинаковыми флагами компилятора и компилятора.
  2. TCP - это поток. Вы должны убедиться, что отправляете всю структуру. Посмотрите документацию для вызова send () - он возвращает количество отправленных байтов - которое может быть меньше, чем вы сказали. То же самое на стороне получателя. То, что вы отправили структуру с одним вызовом отправки, не означает, что вы получите его с одним вызовом recv. Чтобы получить все кусочки, потребуется несколько вызовов recv.
1 голос
/ 14 ноября 2009

Ну ... если вы делаете это правильно, отправлять структуры по сети довольно сложно.

Карл прав - вы можете отправить структуру через сеть, сказав:

send(socket, (char*)my_struct, sizeof(my_struct), 0);

Но вот в чем дело:

  • sizeof (my_struct) может меняться между клиентом и сервером. Компиляторы часто выполняют некоторые операции заполнения и выравнивания, поэтому, если вы не определите выравнивание явно (возможно, с помощью #pragma pack ()), этот размер может отличаться.
  • Другая проблема, как правило, связана с порядком байтов. Некоторые машины с прямым порядком байтов, а другие - с прямым порядком байтов, поэтому расположение байтов может быть другим. На самом деле, если ваш сервер или клиент не работает на оборудовании не от Intel (что, вероятно, не так), то эта проблема существует больше в теории, чем на практике.

Таким образом, решение, которое часто предлагают люди, состоит в том, чтобы иметь подпрограмму, которая сериализует структуру. То есть он отправляет struct по одному элементу данных за раз, гарантируя, что клиент и сервер только отправляют () и recv () точное указанное число байтов, которые вы кодируете в своей программе.

0 голосов
/ 26 января 2010

Отправьте данные в виде текстового файла, а затем расшифруйте их после получения. Это лучший способ, если вы хотите, чтобы ваши данные отправлялись !!

0 голосов
/ 14 ноября 2009

В общем, это плохая идея, даже если ваш клиент и ваш сервер оказываются одинаково размещающими структуру в памяти.

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

0 голосов
/ 14 ноября 2009

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

...