Отправка структуры через TCP (C-программирование)

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

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

send(socket, string, string_size, 0);

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

7 ответов

Решение

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

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

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

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

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

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

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

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

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

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

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

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

Вы можете, но вы должны знать о 2 важных вещах.

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

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

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

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

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

Другие вопросы по тегам