第一个DGRAM没有IP

时间:2013-01-30 01:07:21

标签: 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);

1 个答案:

答案 0 :(得分:5)

您需要将addr_len初始化为sizeof(their_addr)。根据手册页:

  

参数 addrlen是一个值结果参数调用者应初始化   在调用与src_addr 关联的缓冲区大小之前,和   返回时修改以指示源地址的实际大小。归来了   如果提供的缓冲区太小,则地址被截断;在这种情况下,addrlen会   返回一个大于提供给调用的值。

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