用 C/C++ 创建和发送数据包
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5795283/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Creating and sending data packets in C/C++
提问by Chad Johnson
Let's say I want to send the following data to a socket using C or C++, all in one packet:
假设我想使用 C 或 C++ 将以下数据发送到套接字,全部在一个数据包中:
Headers
-------
Field 1: 2 byte hex
Field 2: 2 byte hex
Field 3: 4 byte hex
Data
----
Field1 : 2 byte hex
Field1 : 8 byte hex
What would the code typically look like to create and send the packet containing all this data?
创建和发送包含所有这些数据的数据包的代码通常是什么样的?
回答by Rob?
Let's suppose that your program is already organized to have the header in one struct
and the data in another struct
. For example, you might have these data structures:
假设您的程序已经被组织成将标题放在一个文件中struct
,将数据放在另一个文件中struct
。例如,您可能有以下数据结构:
#include <stdint.h>
struct header {
uint16_t f1;
uint16_t f2;
uint32_t f3;
};
struct data {
uint16_t pf1;
uint64_t pf2;
};
Let's call this organization "host format". It really doesn't matter to me what the host format is, as long as it is useful to the rest of your program. Let's call the format that you will pass to the send()
call "network format". (I chose these names to match the htons
(host-to-network-short) and htonl
(host-to-network-long) names.)
我们称这个组织为“主机格式”。主机格式是什么对我来说真的无关紧要,只要它对程序的其余部分有用即可。让我们将您将传递给调用的格式send()
称为“网络格式”。(我选择了这些名称来匹配htons
(host-to-network-short)和htonl
(host-to-network-long)名称。)
Here are some conversion functions that we might find handy. Each of these converts your host format structures to a network format buffer.
这里有一些我们可能会觉得方便的转换函数。这些中的每一个都将您的主机格式结构转换为网络格式缓冲区。
#include <arpa/inet.h>
#include <string.h>
void htonHeader(struct header h, char buffer[8]) {
uint16_t u16;
uint32_t u32;
u16 = htons(h.f1);
memcpy(buffer+0, &u16, 2);
u16 = htons(h.f2);
memcpy(buffer+2, &u16, 2);
u32 = htonl(h.f3);
memcpy(buffer+4, &u32, 4);
}
void htonData(struct data d, char buffer[10]) {
uint16_t u16;
uint32_t u32;
u16 = htons(d.pf1);
memcpy(buffer+0, &u16, 2);
u32 = htonl(d.pf2>>32);
memcpy(buffer+2, &u32, 4);
u32 = htonl(d.pf2);
memcpy(buffer+6, u32, 4);
}
void htonHeaderData(struct header h, struct data d, char buffer[18]) {
htonHeader(h, buffer+0);
htonData(d, buffer+8);
}
To send your data, do this:
要发送您的数据,请执行以下操作:
...
char buffer[18];
htonHeaderData(myPacketHeader, myPacketData, buffer);
send(sockfd, buffer, 18, 0);
...
Again, you don't have to use the header
and data
structs that I defined. Just use whatever your program needs. The key is that you have a conversion function that writes all of the data, at well-defined offsets, in a well-defined byte order, to a buffer, and that you pass that buffer to the send() function.
同样,您不必使用我定义的header
anddata
结构。只需使用您的程序需要的任何东西。关键是您有一个转换函数,它以明确定义的偏移量、明确定义的字节顺序将所有数据写入缓冲区,然后将该缓冲区传递给 send() 函数。
On the other side of the network connection, you will need a program to interpret the data it receives. On that side, you need to write the corresponding functions (ntohHeader
, etc). Those function will memcpy
the bits out of a buffer and into a local variable, which it can pass to ntohs
or ntohl
. I'll leave those functions for you to write.
在网络连接的另一端,您需要一个程序来解释它接收到的数据。在那一边,您需要编写相应的函数(ntohHeader
等)。这些函数将从memcpy
缓冲区中取出位并放入一个局部变量中,它可以传递给ntohs
或ntohl
。我会把这些函数留给你写。
回答by Mat
Well, typically it would look like it's preparing that packet structure into a memory buffer (making judicious calls the the htonl
family of functions).
好吧,通常看起来它正在将数据包结构准备到内存缓冲区中(明智地调用htonl
函数系列)。
If would then use the send
, sendto
, sendmsg
or write
functions, hopefully with a lot of care taken with the length of the buffer and good error handling/reporting.
If 将使用send
, sendto
,sendmsg
或write
函数,希望对缓冲区的长度和良好的错误处理/报告非常小心。
(Or one of the Win32 apis for the send, if that is the target plateforms.)
(或用于发送的 Win32 apis 之一,如果这是目标平台。)
You'll find a good presentation about all this at Beej's Guide to Network Programming.
您可以在Beej 的网络编程指南中找到关于所有这些的很好的介绍。
Specifially for the byte packing part (with endian consideration), look at the serializationtopic. (There's way moredetail in that section than what you need for plain fixed-size integer data types.
特别是字节打包部分(有endian考虑),看序列化主题。(该部分比普通固定大小的整数数据类型所需的更多细节。
回答by Matt Kline
The code would look different depending on the OS's networking library (*nix uses Berkeley sockets, Windows uses Winsock, etc.). However, you could create a struct containing all the data you wanted to send in a packet, e.g.,
根据操作系统的网络库,代码看起来会有所不同(*nix 使用Berkeley sockets,Windows 使用Winsock等)。但是,您可以创建一个包含要在数据包中发送的所有数据的结构,例如,
typedef struct
{
short field1;
short field2;
int field3;
} HeaderStruct;
typedef struct
{
short field1;
long long field2;
} PacketDataStruct;
assuming a 32-bit int size.
假设 32 位 int 大小。
Edit:
编辑:
As someone kindly reminded me in the comments, don't forget about converting to and from Network Order. Networking libraries will have functions to assist with this, such as ntohs
, nothl
, htons
, and htonl
.
正如有人在评论中提醒我的那样,不要忘记在Network Order 之间进行转换。网络图书馆将拥有的功能,以协助这一点,比如ntohs
,nothl
,htons
,和htonl
。
回答by Mark Wilkins
One simple answer is that it would be sent in the format that the receiver expects. That begs the question a bit, though. Assuming the data is a fixed size as shown and the receiving end expects, then you could use a packed (1 byte alignment) structure and store the data in each field. The reason for using 1 byte alignment is that it is typically easier to make sure both ends are expecting the same data. Without 1 byte alignment, then the structure would possibly look different based on compiler options, 32-bit versus 64-bit architecture, etc.) And, typically, it is expected that you would send the values in network byte order if the hex values are integers. You can use functions such as htons
and htonl
(and possibly htobe64
if available) to convert them.
一个简单的答案是它将以接收者期望的格式发送。不过,这有点回避问题。假设数据是如图所示的固定大小并且接收端期望,那么您可以使用打包(1 字节对齐)结构并将数据存储在每个字段中。使用 1 字节对齐的原因是通常更容易确保两端期待相同的数据。如果没有 1 字节对齐,则结构可能会根据编译器选项、32 位与 64 位体系结构等而不同。是整数。您可以使用htons
和htonl
(htobe64
如果可用的话)等函数来转换它们。
Assuming that the data is in the structure with the desired byte order, then the send call may be something like this:
假设数据在具有所需字节顺序的结构中,那么发送调用可能是这样的:
ret = send( socket, &mystruct, sizeof( mystruct ), 0 );
That assumes that mystruct
is declared as an instance of the structure as opposed to a pointer to the structure.
假设它mystruct
被声明为结构的实例,而不是指向结构的指针。