程序不在指定端口发送 UDP 包
Program does not send UDP package on specified port
我是套接字编程的新手。我想将 UDP 包发送到网络中另一台 PC 上的特定端口。当我使用 Wireshark 分析我的网络流量时,我看到传出包中的端口号与我在代码中指定的端口号不同。
使用 port=10000,它发送到的实际端口是 4135。当我将它更改为 port=15000(只是为了尝试不同的东西)时,它被发送到端口 38970。
wireshark 显示的端口号必须是真实的,因为设置为侦听这些端口(4135 或 38970)的接收程序确实对发送的数据包做出反应,尽管接收到的数据看起来像乱码(控制台显示未知字符,调试控制台显示“15I11^H1...”)。
知道为什么吗?
我 运行 在连接到虚拟网络中其他 VM 的 Debian VM 上进行此操作。一个使用 TCP 的非常相似的程序工作得很好。
#include <sys/types.h> //Various types, including ssize_t
#include <sys/socket.h> //Types, macros and functions for sockets
#include <netinet/in.h> //Types, including sockaddr_in, macros
#include <arpa/inet.h> //Types and functions, including inet_aton()
#include <unistd.h> //Types, macros and functions for Unix/Posix
#include <stdlib.h> //GP types, macros and functions
#include <stdio.h> //IO operations (streams)
#include <string.h> //Functions for string operations
#define BC_ADDR "192.168.1.255"
int main(int argc, char** argv) {
int clientSocket;
const int setBroadcast = 1;
in_port_t port = 10000;
struct sockaddr_in broadcastAddr;
int broadcastAddrLen = sizeof(struct sockaddr_in);
const char* msg = "Hello World";
//Create a new UDP socket
clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if(clientSocket > 0) {
printf("Socket created successfully\n");
}
else {
printf("Failure during socket creation\n");
exit(EXIT_FAILURE);
}
//Set socket options to allow broadcasts
int setSockOptStatus = setsockopt(clientSocket, SOL_SOCKET,
SO_BROADCAST, &setBroadcast, sizeof(setBroadcast));
if(setSockOptStatus != 0) {
printf("Error setting socket options!");
close(clientSocket);
return EXIT_FAILURE;
}
//Form boradcast address structure
broadcastAddr.sin_family = AF_INET;
broadcastAddr.sin_port = port;
broadcastAddr.sin_addr.s_addr = inet_addr(BC_ADDR);
//Send broadcast message
sendto(clientSocket, msg, strlen(msg)+1, 0,
(struct sockaddr*) &broadcastAddr, broadcastAddrLen);
//Close socket and exit program
close(clientSocket);
return EXIT_SUCCESS;
}
问题在于您如何设置端口:
broadcastAddr.sin_port = port;
存储在struct sockaddr_in
中的IP地址和端口号必须都是网络字节顺序,这是big-endian字节顺序,即最高有效字节在前。您的机器显然使用小端字节顺序,即最低有效字节在前,因此通过将端口号直接分配给 sin_port
成员,表示转换未完成。
如果您查看预期端口号和实际端口号的十六进制表示,这一点会更加明显:
- 10000d = 2710h, 4135d = 1027h
- 15000d = 3a98h, 38970 = 983ah
您需要调用 htons()
函数,该函数将 16 位值从主机字节顺序转换为网络字节顺序:
broadcastAddr.sin_port = htons(port);
我是套接字编程的新手。我想将 UDP 包发送到网络中另一台 PC 上的特定端口。当我使用 Wireshark 分析我的网络流量时,我看到传出包中的端口号与我在代码中指定的端口号不同。 使用 port=10000,它发送到的实际端口是 4135。当我将它更改为 port=15000(只是为了尝试不同的东西)时,它被发送到端口 38970。
wireshark 显示的端口号必须是真实的,因为设置为侦听这些端口(4135 或 38970)的接收程序确实对发送的数据包做出反应,尽管接收到的数据看起来像乱码(控制台显示未知字符,调试控制台显示“15I11^H1...”)。
知道为什么吗?
我 运行 在连接到虚拟网络中其他 VM 的 Debian VM 上进行此操作。一个使用 TCP 的非常相似的程序工作得很好。
#include <sys/types.h> //Various types, including ssize_t
#include <sys/socket.h> //Types, macros and functions for sockets
#include <netinet/in.h> //Types, including sockaddr_in, macros
#include <arpa/inet.h> //Types and functions, including inet_aton()
#include <unistd.h> //Types, macros and functions for Unix/Posix
#include <stdlib.h> //GP types, macros and functions
#include <stdio.h> //IO operations (streams)
#include <string.h> //Functions for string operations
#define BC_ADDR "192.168.1.255"
int main(int argc, char** argv) {
int clientSocket;
const int setBroadcast = 1;
in_port_t port = 10000;
struct sockaddr_in broadcastAddr;
int broadcastAddrLen = sizeof(struct sockaddr_in);
const char* msg = "Hello World";
//Create a new UDP socket
clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
if(clientSocket > 0) {
printf("Socket created successfully\n");
}
else {
printf("Failure during socket creation\n");
exit(EXIT_FAILURE);
}
//Set socket options to allow broadcasts
int setSockOptStatus = setsockopt(clientSocket, SOL_SOCKET,
SO_BROADCAST, &setBroadcast, sizeof(setBroadcast));
if(setSockOptStatus != 0) {
printf("Error setting socket options!");
close(clientSocket);
return EXIT_FAILURE;
}
//Form boradcast address structure
broadcastAddr.sin_family = AF_INET;
broadcastAddr.sin_port = port;
broadcastAddr.sin_addr.s_addr = inet_addr(BC_ADDR);
//Send broadcast message
sendto(clientSocket, msg, strlen(msg)+1, 0,
(struct sockaddr*) &broadcastAddr, broadcastAddrLen);
//Close socket and exit program
close(clientSocket);
return EXIT_SUCCESS;
}
问题在于您如何设置端口:
broadcastAddr.sin_port = port;
存储在struct sockaddr_in
中的IP地址和端口号必须都是网络字节顺序,这是big-endian字节顺序,即最高有效字节在前。您的机器显然使用小端字节顺序,即最低有效字节在前,因此通过将端口号直接分配给 sin_port
成员,表示转换未完成。
如果您查看预期端口号和实际端口号的十六进制表示,这一点会更加明显:
- 10000d = 2710h, 4135d = 1027h
- 15000d = 3a98h, 38970 = 983ah
您需要调用 htons()
函数,该函数将 16 位值从主机字节顺序转换为网络字节顺序:
broadcastAddr.sin_port = htons(port);