我正在研究一个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);
答案 0 :(得分:5)
您需要将addr_len
初始化为sizeof(their_addr)
。根据手册页:
参数 addrlen是一个值结果参数,调用者应初始化 在调用与src_addr 关联的缓冲区大小之前,和 返回时修改以指示源地址的实际大小。归来了 如果提供的缓冲区太小,则地址被截断;在这种情况下,addrlen会 返回一个大于提供给调用的值。
由于您没有初始化addr_len
,因此它似乎取值为0(这是高度未定义的行为)。在这种情况下,recvfrom()
将不会填充their_addr
缓冲区,但是手册页指示addr_len
将返回大于提供给调用的值。因此,在第一次调用addr_len
后,将允许下一次调用recvfrom()
的值正确填充their_addr
缓冲区。依靠这个是不安全的。