Как отправить структуру через UDP и получить на другой стороне?

#c #sockets #networking #udp

#c #сокеты #сеть #udp

Вопрос:

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

 struct data_packet{
   unsigned char seqnumber; 
   char data[500]; 
}

struct data_packet packettosend; 
packettosend.seqnumber = '0'
packettosend.data = 'some binary data' (this could be any length from 0 bytes to 500 bytes) 

//sender code 
char buffer[501]; 
memcpy(buffer, amp;packettosend, sizeof(packetosend)); 
int s = sendto(socketfd, buffer, sizeof(buffer), 0 , .......other params); 

//receiver code
char recvbuffer[501];
int t = recvfrom(recvsocketdf, recvbuffer, 501, 0 ....other params);
  
How do I set up my receiver to receive the data and save it on a `struct data_packet`?    
 

Seqnumber — это 1-байтовый символ, а данные могут составлять от 0 байт до 500 байт.

Я использую sendto для отправки буфера и recvfrom получения буфера на другом конце.

Как я могу получить свой seqnumber и данные на принимающей стороне? Я очень новичок в программировании на C и Socket. Я ценю любую помощь.

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

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

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

3. Ну, вы получаете только столько, сколько отправили, поэтому чтение чего-либо сверх этого является ошибкой. recvfrom сообщает вам, сколько байтов было получено, и вы должны использовать эту информацию.

Ответ №1:

Мое первое предложение — обнулить ваш буфер перед его заполнением и отправкой, просто чтобы избежать мусорных значений. И вам нужно определить протокол — вы можете отправлять и получать только необработанные байты по сети. Сделайте так, чтобы принимающая сторона интерпретировала первый байт как порядковый номер, а остальные — как само фактическое сообщение. Это можно сделать, просто приведя recvbuffer в a struct data_packet , поскольку базовый байтовый макет тот же.

Ответ №2:

Возможная проблема:

Код, вероятно, записывается за пределы своих границ из-за struct заполнения.

 struct data_packet{
   unsigned char seqnumber; 
   // There maybe padding here.
   char data[500]; 
   // There maybe padding here.
}

struct data_packet packettosend; 
char buffer[501];  // May be too small for `packettosend`
memcpy(buffer, amp;packettosend, sizeof(packetosend)); 
 

Альтернатива: сделать buffer[] , конечно, достаточно большой

 // char buffer[501];
char buffer[sizeof packetosend];
 

Для отправки только данных, а не, конечно, не каких-либо дополнений:

Упакуйте данные с помощью ключевого слова, специфичного для реализации (если доступно)

 // struct data_packet{
packed struct data_packet{
 

Или выполнить 2 отправки

 int s1 = sendto(socketfd, amp;buffer.seqnumber, sizeof buffer.seqnumber, ...);
int s2 = sendto(socketfd, buffer.data, sizeof buffer.data, ...);
 

Или скопировать тщательно

 #define SEQ_DATA (sizeof buffer.seqnumber   sizeof buffer.data)
char buffer[SEQ_DATA]; 
memcpy(buffer, amp;buffer.seqnumber, sizeof buffer.seqnumber);
memcpy(buffer   sizeof buffer.seqnumber, buffer.data, sizeof buffer.data);
int s = sendto(socketfd, buffer, sizeof buffer, ...);
 

Отрегулируйте recvbuffer[] размер, чтобы соответствовать.

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

1. Спасибо вам за то, что уделили этому время. Это выглядит очень многообещающе. Есть определенные условия, которым я должен следовать. Я могу выполнить только 1 отправку. И размер пакета данных, который я получаю, не может превышать 501 байт. Как мне решить эту проблему?

2. @MaheshKhanal Используйте последнее «копировать осторожно»

3. Спасибо. Копирование работает так, как задумано. Я очень ценю это.

Ответ №3:

Я согласен с Деннисом Афанасьевым. Чтобы уточнить стратегию приведения, прочитайте все 501 байт (включая частичное / неполное чтение), а затем преобразуйте в переменную указателя, например:

 struct data_packet *dataRecv = (struct data_packet *)amp;recvbuffer[0];
 

Затем вы можете разыменовать dataRecv для доступа к структуре, как в dataRecv-> seqnumber и dataRecv-> data .