第一个DGRAM没有IP

Rya*_*yan 0 c sockets

我正在研究的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);
Run Code Online (Sandbox Code Playgroud)

Jar*_*edC 5

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

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

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