这里的“十六进制”通常有两种理解:

(图片来源网络,侵删)
- 发送字符串形式的十六进制:你想发送的字节是
0x48, 0x65, 0x6C, 0x6C, 0x6F,但你实际发送的是 ASCII 字符串"48656C6C6F"。 - 发送原始的十六进制字节值:这才是最常见的情况,你想直接发送
0x48, 0x65, 0x6C, 0x6C, 0x6F这五个字节本身,而不是它们的字符串表示。
下面我将详细讲解这两种情况,并提供完整的代码示例。
发送原始的十六进制字节值 (最常用)
这是真正的“十六进制数据”传输,你的数据在内存中就是以字节形式存在的,sendto 的任务就是把这些字节原封不动地通过网络发出去。
核心思想
- 准备数据:将你的十六进制数(如
0x31, 0x32, 0x33)存入一个char数组或uint8_t数组中。char在 C 语言中本质上是1字节,非常适合此场景。 sendto调用:将这个数组的地址作为sendto的buf参数,数组的长度作为len参数。
示例:发送 0x31, 0x32, 0x33, 0x0A
假设我们要发送四个字节:0x31, 0x32, 0x33, 0x0A,在 ASCII 码中,这四个字节分别对应字符 '1', '2', '3', '\n'。
这是一个完整的 UDP 发送端示例:

(图片来源网络,侵删)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
// 1. 创建 UDP socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
// 2. 定义目标服务器地址和端口
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
// IPv4
servaddr.sin_family = AF_INET;
// IP 地址 (例如本地回环地址 127.0.0.1)
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
// 端口号 (8080)
servaddr.sin_port = htons(8080);
// 3. 准备要发送的十六进制数据
// 这是你想要发送的原始字节
// 0x31, 0x32, 0x33, 0x0A 对应 "123\n"
char hex_data[] = {0x31, 0x32, 0x33, 0x0A};
// 或者,如果你有十六进制字符串,可以这样转换
// const char *hex_str = "3132330A";
// char hex_data[4];
// for (int i = 0; i < 4; i++) {
// sscanf(hex_str + 2*i, "%2hhx", &hex_data[i]);
// }
size_t data_len = sizeof(hex_data);
// 4. 使用 sendto 发送数据
// ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
// const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sent_bytes = sendto(sockfd,
(const void *)hex_data,
data_len,
0,
(const struct sockaddr *)&servaddr,
sizeof(servaddr));
if (sent_bytes < 0) {
perror("sendto failed");
} else {
printf("Successfully sent %zd bytes.\n", sent_bytes);
// 打印发送的内容(以十六进制形式显示)
printf("Sent data: ");
for (int i = 0; i < data_len; i++) {
printf("%02X ", (unsigned char)hex_data[i]);
}
printf("\n");
}
// 5. 关闭 socket
close(sockfd);
return 0;
}
代码解释
char hex_data[] = {0x31, 0x32, 0x33, 0x0A};- 这是最关键的一步,我们直接定义了一个
char数组,并用十六进制字面量初始化它,这些值就是我们要发送的原始数据。
- 这是最关键的一步,我们直接定义了一个
- *`sendto(sockfd, (const void )hex_data, ...)`**
buf参数是hex_data,即我们存放数据的数组首地址。len参数是sizeof(hex_data),即数组的长度(字节数)。sendto会将hex_data数组中的每一个字节(0x31,0x32,0x33,0x0A)依次发送出去。
发送字符串形式的十六进制
你可能需要将一串十六进制数字("A1B2C3")作为文本消息发送,接收方收到的是字符 'A', '1', 'B', '2', 'C', '3',而不是字节 0xA1, 0xB2, 0xC3。
核心思想
- 准备数据:直接使用一个包含十六进制字符的字符串,
char data[] = "A1B2C3";。 sendto调用:与普通字符串发送完全相同,sendto会发送字符串的 ASCII 码值。
示例:发送字符串 "A1B2C3"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main() {
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
servaddr.sin_port = htons(8080);
// 准备要发送的字符串数据
// 注意:这是字符 'A', '1', 'B', '2', 'C', '3',而不是字节 0xA1, 0xB2, 0xC3
char str_data[] = "A1B2C3";
size_t data_len = strlen(str_data); // 使用 strlen 获取字符串长度
ssize_t sent_bytes = sendto(sockfd,
(const void *)str_data,
data_len,
0,
(const struct sockaddr *)&servaddr,
sizeof(servaddr));
if (sent_bytes < 0) {
perror("sendto failed");
} else {
printf("Successfully sent %zd bytes.\n", sent_bytes);
printf("Sent string data: %s\n", str_data);
printf("Sent data in hex: ");
for (int i = 0; i < data_len; i++) {
printf("%02X ", (unsigned char)str_data[i]);
}
printf("\n"); // 会输出 41 31 42 32 43 33
}
close(sockfd);
return 0;
}
代码解释
char str_data[] = "A1B2C3";- 这里定义的是一个标准的 C 字符串,编译器会将其存储为
'A','1','B','2','C','3','\0'。
- 这里定义的是一个标准的 C 字符串,编译器会将其存储为
sendto发送的是这些字符的 ASCII 码:'A'->0x41'1'->0x31'B'->0x42- ... 以此类推。
- 接收方收到的是6个字节(不包括
'\0'是0x41, 0x31, 0x42, 0x32, 0x43, 0x33。
总结与对比
| 特性 | 发送原始字节值 | 发送字符串形式的十六进制 |
|---|---|---|
| 数据准备 | char data[] = {0xA1, 0xB2, 0xC3}; |
char data[] = "A1B2C3"; |
sendto 发送内容 |
原始字节 0xA1, 0xB2, 0xC3 |
字符的ASCII码 'A'(0x41), '1'(0x31), ... |
| 网络传输 | 3个字节:A1 B2 C3 |
6个字节:41 31 42 32 43 33 |
| 用途 | 二进制协议、传感器数据、控制指令等 | 发送可读的十六进制文本、调试信息等 |
| 转换 | 如果从字符串转换,需要手动解析 | 无需转换,直接发送 |
如何选择?
- 如果你的数据是二进制格式(图像、传感器读数、自定义协议的数据包),请使用场景一,这是最直接、最高效的方式。
- 如果你的数据本质上是文本是十六进制字符(发送一个MAC地址
"AA:BB:CC:DD:EE:FF"或一个校验和"7F"),请使用场景二。
希望这个详细的解释和示例能帮助你理解在 C 语言中如何使用 sendto 发送十六进制数据!
