2009-12-11 5 views
2

Как передать следующий формат сообщения от UDP-клиента на UDP-сервер?Передача структур с использованием sento()

----------------------------- 
|Ver|p|fff| length| checksum| 
---------------------------- 
| Customer id    | 
----------------------------- 
| Amount     | 
----------------------------- 
|other      | 
----------------------------- 

Как написать необработанные данные из структуры на провод?

+1

Если вы хотите reliablility, не используйте UDP. Попытки сделать UDP надежными в основном связаны с повторной реализацией TCP, что не является разумной задачей. – 2009-12-11 19:21:51

+0

Почему бы вам просто не использовать tcp, если вам нужна надежность? У вас возникла проблема с объявлением разметки с указанными полями, заполнением его экземпляра и записью его в буфер? – begray

+0

http://stackoverflow.com/questions/107668/what-do-you-use-when-you-need-reliable-udp – sylvanaar

ответ

3

См связанные вопрос/ответы здесь: Sending structure using recvfrom() and sendto()

Имейте в виду, что если клиент и сервер имеют различные архитектуры машины (Big Endian против Little Endian) или даже разные компиляторы/интерпретаторы затем отправить сырой структуры не хорошая идея. Я видел случаи, когда машины той же архитектуры не рассматривали структуру структуры так же, потому что компиляторы, используемые для кода клиента и сервера, оптимизировали хранилище структуры по-разному.

Поэтому вместо отправки всей структуры рассмотрим кодирование каждого поля в буфер с помощью htons(), htonl() для целых чисел, longs и т. Д. Затем отправьте этот буфер, а не исходную структуру. На стороне сервера декодируйте полученный буфер, используя ntohs(), ntohl() и т. Д. Для восстановления структуры.

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

Вместо этого вы можете использовать TCP-соединение и, возможно, его открывать для обмена дополнительной информацией между клиентом и сервером. В этом случае вы, вероятно, захотите добавить некоторые значения разделителя между сообщениями и «избежать» этих разделителей, когда они произойдут в служебных нагрузках буфера сообщений.Причина этого в том, что TCP действительно дает вам двунаправленный поток байтов, поэтому вам нужно быть осторожным, когда заканчивается одно сообщение, а затем начинается следующее. UDP является «ориентированным на сообщения» таким образом, что один recvfrom получит одно полное сообщение, тогда как при TCP, когда вы читаете байты из сокета, вы можете читать конец одного сообщения и первые несколько байтов следующего сообщения, таким образом, необходимость для разделителей.

-1

Вам необходимо будет эмулировать части TCP, см. Все section 5 в этом FAQ. Тем не менее, как только вы это сделали, изучите использование sendto, как вы форматируете данные, полностью зависит от вас и как вы собираетесь его обрабатывать, но имейте в виду, что сокеты очень хороши при отправке байтовых потоков, а не многое другое.

+0

Почему, по-вашему, OP должен эмулировать части TCP? – cigarman

1

У вас есть два варианта.

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

2) Напишите исходные данные на провод. Если вы сделаете это, вы захотите убедиться, что все числа находятся в сетевом порядке (см. Ntohl(), htonl(), ntohs(), htons()).

+0

Как написать исходные данные из структуры на провод? –

1

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

1) Либо скопировать структуру в буфер и передать указатель на буфер для SENTO

// rough example (not tested) 
unsigned char buffer[1024]; 
struct yourstruct_t data; 
memcpy_s(buffer, sizeof(buffer), &data, sizeof(yourstruct_t)); 
sendto(socket, buffer, sizeof(yourstruct_t), ...); 

2) Пропустите-структуру непосредственно SENTO

// rough example (not tested) 
struct yourstruct_t data; 
sendto(socket, (unsigned char *) &data, sizeof(yourstruct_t), ...); 

Проверить эту Socket tutorial.

0

Как указывали другие, вы должны быть очень осторожны с энтузиазмом (особенно с полем длины) при отправке через платформы. Я полагаю, вы также должны быть осторожны со структурой упаковки и выравниванием.

Я бы создал следующую структуру и бросил ее как char * в sendto/recvfrom.
Вы не указали конкретные типы полей, поэтому я принял unsigned char.

//assume the following structure on both the server and client 
#pragma pack(1) //windows only 
typedef struct _data{ 
    unsigned char Ver; 
    unsigned char p; 
    unsigned char fff; 
    unsigned short length; 
    unsigned short checksum; 
    unsigned long Customer_id; 
    unsigned long Amount; 
    unsigned char other[1485]; //1500 (normal MTU)-15 used 
} data; 

//on the server 
data data_to_send; 
data_to_send.length=sizeof(data); 
data_to_send.Ver=1; 
data_to_send.p=1; 
//[...] fill in other data_to_send fields here 
data_to_send.length += 64; //just an example of using 64 bytes in "other" 
data_to_send.checksum=calcChecksum(data_to_rx,data_to_rx.length); 
sendto(socket, (char *) &data_to_send, data_to_send.length, ...);  

//on the client 
data data_to_rx; 
unsigned short checksum; 
n=recvfrom(socket,(char *)&data_to_rx,sizeof(data),...); 
//validate the incoming data_to_rx fields 
if(data_to_rx.Ver!=1) //drop it 
checksum=calcChecksum(data_to_rx,data_to_rx.length); 
if(checksum!=data_to_rx.checksum) //drop it 
[...] 
Смежные вопросы