程序不在指定端口发送 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);