使用sento()传递结构

发布于 2024-08-14 15:52:40 字数 357 浏览 5 评论 0原文

如何将以下消息格式从 UDP 客户端传递到 UDP 服务器?

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

如何将结构中的原始数据写入线路?

How do I pass following message format from a UDP client to a UDP server?

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

how do I write raw data from a structure onto the wire?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

毁梦 2024-08-21 15:52:40

请参阅此处的相关问题/答案:
使用recvfrom()和sendto()发送结构

请记住,如果客户端和服务器具有不同的机器体系结构(Big Endian 与 Little Endian),甚至不同的编译器/解释器,那么发送原始结构不是一个好主意。我见过一些情况,相同架构的机器没有看到相同的结构布局,因为用于客户端和服务器代码的编译器以不同的方式优化了结构存储。

因此,不要发送整个结构,而是考虑使用 htons()、htonl() 将每个字段编码到缓冲区中以表示整数、长整型等。然后发送该缓冲区而不是原始结构。在服务器端使用 ntohs()、ntohl() 等解码接收到的缓冲区以重建结构。

使用 UDP,您必须意识到网络可能会丢失消息。如果您的客户端和服务器位于同一本地 LAN 上,则丢失数据包的可能性很小。如果客户端和服务器通过互联网进行通信,那么这种可能性就会大大增加。您可以添加确认消息和超时,但随后您将开始重新发明 TCP 等可靠传输(例如,您需要处理原始消息成功但仅丢失确认的情况。)这并不是一件可怕的事情去做,但要意识到你正在做什么。

您可以改为使用 TCP 连接并可能保持其打开状态以在客户端和服务器之间交换更多信息。在这种情况下,您可能需要在消息之间添加一些分隔符值,并在这些分隔符出现在消息缓冲区有效负载中时“转义”这些分隔符。原因是 TCP 确实为您提供了双向字节流,因此您必须小心一个消息的结束位置和下一个消息的开始位置。 UDP是“面向消息的”,这样一个recvfrom将为您提供一条完整的消息,而使用TCP时,当您从套接字读取字节时,您可能会读取一条消息的尾部和下一条消息的前几个字节,因此需要用于分隔符。

See related question/answers here:
Sending structure using recvfrom() and sendto()

Keep in mind that if the client and server have different machine architectures (Big Endian vs Little Endian) or even different compilers/interpreters then sending a raw structure is not a good idea. I have seen cases where machines of the same architecture did not view a structure layout the same because the compilers used for the client and server code had optimized the struct storage differently.

So instead of sending the whole struct, consider encoding each field into a buffer using htons(), htonl() for integers, longs, etc. Then send that buffer rather than the original struct. On the server side decode the received buffer using ntohs(), ntohl() etc.. to reconstruct the struct.

Using UDP you will have to be aware that the network may lose the message. If your client and server on on the same local LAN the chances of a lost packet are low. If the client and server are talking across the Internet then the chances go up considerably. You can add acknowledgment messages and timeouts, but then you are starting down the path of re-inventing a reliable transport like TCP (e.g. you need to handle cases where the original message made it but only the acknowledgement was lost.) Not a terrible thing to do, but just be aware of what you are getting into.

You can instead use a TCP connection and possibly keeping it open to exchange more information between client and server. In this case you will probably want to add some delimiter values between messages and "escape" those delimiters when they occur within the message buffer payloads. The reason for this is that TCP really gives you a bidirectional byte stream, so you have to be careful about where one message ends and the next begins. UDP is "message oriented" such that one recvfrom will get you one complete message, whereas with TCP when you read bytes from the socket you could be reading the tail end of one message and the first few bytes of the next message, thus the need for delimiters.

迷爱 2024-08-21 15:52:40

你有两个选择。

1) 您可以在发送前将结构编组为有线格式,然后在接收后将其解组。除非您发送大量数据(或经常发送少量数据),否则开销应该不会很明显。

2) 将原始数据写入线路。如果这样做,您需要确保所有数字都按网络顺序排列(请参阅 ntohl()、htonl()、ntohs()、htons())。

You have two choices.

1) You can marshall the structure into a wire format before sending and then unmarshall it after receiving. Unless you are sending a lot of data (or sending a little data very often), the overhead should not be noticeable.

2) Write the raw data onto the wire. If you do this, you'll want to make sure any numbers are in network order (see ntohl(), htonl(), ntohs(), htons()).

金橙橙 2024-08-21 15:52:40

我假设你有一个这样的结构。如果要传输到不同的体系结构,您将需要处理任何大/小端问题。

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), ...);

查看此套接字教程

I'm assuming you have a structure for this. You will need to handle any big/little endian issues if you are transmitting to different architectures.

1) Either copy the structure to a buffer and pass the pointer to the buffer to 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) Pass the struct directly to sento

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

Check out this Socket tutorial.

小猫一只 2024-08-21 15:52:40

不过,正如其他人指出的那样,在跨平台发送时,您需要非常小心字节顺序(尤其是长度字段)。我相信,您还需要小心结构打包和对齐。

我将创建以下结构并将其转换为 sendto/recvfrom 中的 char *。
您没有具体说明字段类型,因此我假设为 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
[...]

As others have pointed out, though, you need to be very careful with endianess (especially with the length field) when sending across platforms. You also need to be careful with structure packing and alignment, I believe.

I would create the following structure and cast it as a char * in sendto/recvfrom.
You weren't specific about the field types, so I assumed 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
[...]
日记撕了你也走了 2024-08-21 15:52:40

您需要模拟 TCP 的部分内容,请参阅第 5 节的全部内容那个常见问题解答。也就是说,一旦完成此操作,请考虑使用 sendto,如何格式化数据完全取决于您以及您打算如何处理它,但请记住,套接字非常擅长发送字节流,而不是发送字节流。还有很多其他的。

You will need to emulate parts of TCP, see all of section 5 on that FAQ. That said, once you've done that, look into using sendto, how you format the data is entirely up to you and how you intend to process it, but keep in mind that sockets are very good at sending byte-streams, and not much else.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文