在C/ c++中创建和发送数据包
Creating and sending data packets in C/C++
假设我想使用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
创建和发送包含所有这些数据的数据包的代码通常是什么样子的? 让我们假设你的程序已经组织好了,头文件在一个struct
中,数据在另一个struct
中。例如,您可能有这些数据结构:
#include <stdint.h>
struct header {
uint16_t f1;
uint16_t f2;
uint32_t f3;
};
struct data {
uint16_t pf1;
uint64_t pf2;
};
我们称这种组织为"主机格式"。对我来说,宿主格式是什么并不重要,只要它对程序的其余部分有用就行。我们将传递给send()
的格式称为"网络格式"。(我选择这些名称是为了匹配htons
(主机到网络短)和htonl
(主机到网络长)名称。)
下面是一些我们可能会觉得很方便的转换函数。它们都将您的主机格式结构转换为网络格式缓冲区。
#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);
}
发送你的数据,这样做:
...
char buffer[18];
htonHeaderData(myPacketHeader, myPacketData, buffer);
send(sockfd, buffer, 18, 0);
...
同样,您不必使用我定义的header
和data
结构体。只要使用你的程序需要的任何东西。关键是你有一个转换函数,它将所有的数据,在定义好的偏移量,以定义好的字节顺序,写入缓冲区,并将该缓冲区传递给send()函数。
在网络连接的另一端,您需要一个程序来解释它接收到的数据。在这方面,您需要编写相应的函数(ntohHeader
等)。这些函数将memcpy
缓冲区中的位放入一个局部变量中,该局部变量可以传递给ntohs
或ntohl
。我将把这些函数留给你来写。
嗯,通常情况下,它看起来像是将数据包结构准备到内存缓冲区中(明智地调用htonl
函数族)。
然后使用send
, sendto
, sendmsg
或write
函数,希望非常小心缓冲区的长度和良好的错误处理/报告。
(或用于发送的Win32 api之一,如果这是目标平台。)
你可以在Beej的网络编程指南中找到一个很好的演示。
特别是对于字节打包部分(考虑到端序),请查看序列化主题。(在这一节中,的细节远远超过了普通的固定大小的整数数据类型。
根据操作系统的网络库(*nix使用Berkeley套接字,Windows使用Winsock等),代码看起来会有所不同。但是,您可以创建一个结构体,其中包含您想要在数据包中发送的所有数据,例如
typedef struct
{
short field1;
short field2;
int field3;
} HeaderStruct;
typedef struct
{
short field1;
long long field2;
} PacketDataStruct;
假设为32位整型。
编辑:正如有人在评论中善意地提醒我的那样,不要忘记转换到和退出网络秩序。网络库将具有帮助完成此任务的函数,例如ntohs
、nothl
、htons
和htonl
。
一个简单的答案是,它将以接收方期望的格式发送。不过,这有点回避了问题。假设数据是如图所示的固定大小,并且接收端所期望的,那么您可以使用打包(1字节对齐)结构并将数据存储在每个字段中。使用1字节对齐的原因是,通常更容易确保两端期望相同的数据。如果没有1字节对齐,那么结构可能会根据编译器选项,32位与64位体系结构等而有所不同)并且,通常,如果十六进制值是整数,则预计您将以网络字节顺序发送值。您可以使用htons
和htonl
(如果可用,可能还有htobe64
)等函数来转换它们。
假设数据在具有所需字节顺序的结构中,那么send调用可能是这样的:
ret = send( socket, &mystruct, sizeof( mystruct ), 0 );
假定将mystruct
声明为结构体的实例,而不是指向结构体的指针。
- boost::asio UDP 广播客户端仅接收"fast"数据包
- 如何使用发送数据包所花费的时间计算两个节点之间的距离?
- 发送固定大小的 UDP 数据包
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 在 c++ 中解析数据包数据的最佳方法是什么?
- 接受函数在发送数据包时等待
- 如何在 omnet++ 中发送自定义数据包?
- 数据包访问实践
- 我想知道我是否可以将一个类分配给特定的成员数据并创建该类的实例
- 在C++中创建一个简单的数据包路由器,如何跟踪"客户端"?
- 德拉吉诺 LG01-S 收到异常数据包并停止工作
- 将数据包从C++服务器发送到NodeJs服务器时出现MessagePack解码错误
- 使用C++将UDP数据包存储在Structure中
- FFmpeg av_read_frame从音频流返回数据包
- 为什么操作系统正在更改我的数据包的指定传出端口
- 在C/C 中创建和发送原始数据包
- 原始数据包创建导致 IP 字段顺序不正确
- 在C#/C++中创建数据包筛选器
- 网络数据包创建/解析库
- 在C/ c++中创建和发送数据包