【发布时间】:2016-06-04 15:10:29
【问题描述】:
我用 C 语言编写了一个简短的 TCP 服务器示例,它不断侦听端口 12701 上的连接,并将对等方的 sockaddr.sa_family 的值输出到标准输出。程序在无限循环中调用accept(),它应该在struct sockaddr中填写连接的详细信息,包括sa_family。
但是,对于第一个 TCP 连接,这不会正确发生; sockaddr.sa_family 始终为零。所有后续连接都提供正确的值 2 - 只有第一个是错误的。为什么会这样?我还没有找到任何类似问题的报告,但我怀疑我初始化不正确或误解了 accept() 的参数。
这是程序:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int main(void)
{
struct sockaddr_in saddr =
{
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(12701),
};
// open socket to accept() tcp connections
int accept_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(accept_fd, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in));
listen(accept_fd, SOMAXCONN);
socklen_t addrlen;
struct sockaddr * addr;
for(;;)
{
addr = (struct sockaddr *) malloc(sizeof(struct sockaddr));
int child_fd = accept(accept_fd, addr, &addrlen);
// why is this always zero the first time?
printf("addr->sa_family = %d\n", addr->sa_family);
close(child_fd);
free(addr);
}
return 0;
}
【问题讨论】:
-
在调用
accept之前必须初始化addrlen。另外,为什么要动态分配?这可能只会导致内存泄漏(就像你现在一样)。 -
当调用任何内存分配函数(malloc、calloc、realloc)时,1)不要转换返回值。返回值的类型为
void*,因此可以分配给任何指针。强制转换只会使代码混乱,使理解、调试和维护变得更加困难。 2) 始终检查 (!=NULL) 返回值以确保操作成功。注意:始终将内存分配返回的指针传递给函数free(),以避免内存泄漏(在当前情况下,最终会导致系统崩溃)建议在调用close后立即调用free() -
您对内存泄漏的看法是正确的;这段代码是从一个更大的程序复制而来的,稍后将释放内存。为了将来清楚起见,我已在示例中修复了该问题。