0

我正在使用的 UDP 服务器有一个奇怪的问题。收到的第一个 udp 数据包没有关于数据包来源的信息。随后的 udp 数据包似乎都很好,并正确显示了接收数据包的 ip 地址。我不知道是什么导致了这种行为,可能是一些愚蠢的错误,或者一些晦涩的错误。我在运行 Debian 的 Linux 机器上使用。

fd_set master;
fd_set read_fds;
int fdmax;
int i;
int bytes_sent;
int bytes_recv;
socklen_t addr_len;
struct sockaddr_storage their_addr;

// provides users information needed to connect
serv_info *server_info;
server_info = (serv_info*) serv_config;

// Create UDP listener socket
int info_sock = createDGRAMSocket(NULL, server_info->port, 1);
char buffer[1024];
int len;
int send_response;

FD_SET(info_sock, &master);
fdmax = info_sock;
bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
printf("Info started \n");
while (running) {
    read_fds = master;
    select(fdmax+1, &read_fds, NULL, NULL, NULL);
    for (i = 0; i <= fdmax; i++) {
        if (FD_ISSET(i, &read_fds)) {
            bytes_recv = recvfrom(i, buffer, sizeof(buffer), 0, (struct sockaddr *)&their_addr, &addr_len);
            printf("length %u: %s\n", bytes_recv, buffer);
            send_response = 0;

            switch (buffer[0]) {
                // Handle different packet types

            }

            struct sockaddr_in *sin = (struct sockaddr_in *)&their_addr;
            unsigned char *ip = (unsigned char *)&sin->sin_addr.s_addr;
            printf("IP: %d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);

            if (send_response) {
                bytes_sent = sendto(info_sock, buffer, len, 0, (struct sockaddr *)&their_addr, sizeof(struct sockaddr_storage));
                if (bytes_sent < 0) {
                    printf("[ERROR] Packet Send Failed %d (%s) %d\n", bytes_sent, buffer, len);
                }
            }
        }
    }
};
close(info_sock);
4

1 回答 1

5

您需要初始化addr_lensizeof(their_addr). 根据手册页:

参数addrlen 是一个 value-result 参数调用者应该在调用与 src_addr 关联的缓冲区大小之前对其进行初始化,并在返回时修改以指示源地址的实际大小。如果提供的缓冲区太小,返回的地址会被截断;在这种情况下,addrlen 将返回一个大于提供给调用的值。

由于您没有进行初始化addr_len,因此它的值似乎为 0(这是高度未定义的行为)。在这种情况下,recvfrom()不会填充their_addr缓冲区,但正如手册页所示,addr_len将返回一个大于提供给调用的值。因此,在第一次调用之后,将addr_len采用一个允许下一次调用recvfrom()正确填充their_addr缓冲区的值。但是,依靠它是不安全的。

于 2013-01-30T01:25:33.093 回答