accept()调用不';t初始化sockaddr结构
我用C编写了一个简短的TCP服务器示例,它持续侦听端口12701上的连接,并将对等方的sockaddr.sa_族的值输出到stdout。程序在无限循环中调用accept(),该循环应在accept()调用不';t初始化sockaddr结构,c,sockets,unix,C,Sockets,Unix,我用C编写了一个简短的TCP服务器示例,它持续侦听端口12701上的连接,并将对等方的sockaddr.sa_族的值输出到stdout。程序在无限循环中调用accept(),该循环应在struct sockaddr中填充连接的详细信息,包括sau族 但是,对于第一个TCP连接,这种情况不会正确发生;sockaddr.sau族始终为零。所有后续连接都提供了正确的值2-只有第一个连接是错误的。为什么会发生这种情况?我还没有找到任何类似问题的报告,但我怀疑我初始化了错误的内容或误解了accept()的
struct sockaddr
中填充连接的详细信息,包括sau族
但是,对于第一个TCP连接,这种情况不会正确发生;sockaddr.sau族始终为零。所有后续连接都提供了正确的值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;
}
#包括
#包括
#包括
#包括
#包括
内部主(空)
{
saddr中的结构sockaddr\u=
{
.sin_family=AF_INET,
.sin_addr.s_addr=htonl(INADDR_ANY),
.sin_port=htons(12701),
};
//打开套接字以接受()tcp连接
int accept\u fd=套接字(AF\u INET,SOCK\u STREAM,0);
绑定(accept_fd,(struct sockaddr*)和saddr,sizeof(struct sockaddr_in));
倾听(接受fd,SOMAXCONN);
索克伦·阿德伦;
结构sockaddr*addr;
对于(;;)
{
addr=(struct sockaddr*)malloc(sizeof(struct sockaddr));
int child\u fd=accept(accept\u fd、addr和addrlen);
//为什么第一次总是零?
printf(“addr->sau family=%d\n”,addr->sau family);
关闭(child_fd);
免费(addr);
}
返回0;
}
例如,请查看以下文档:
更具体地说,是addrlen参数的描述。
这是一个inout参数,您必须正确初始化它
addrlen参数是一个值结果参数:调用方必须
初始化它以包含指向的结构的大小(字节)
地址为:;返回时,它将包含对等的实际大小
地址。”
这假定要设置的连接是
AF\u INET
您希望将适合您将侦听套接字绑定到的结构的地址传递给accept()
,即中的struct sockaddr\u
另外,addrlen
需要设置为传递给accept()
的地址的大小
未正确处理对accept()
的调用
在张贴的代码中:
必须检查对accept()
的调用是否失败
必须检查对malloc()
的调用是否失败
分配的内存必须是空闲的
每次调用accept()
之前,必须正确初始化accept()的addrlen
参数
发布的代码一次只能处理一个连接。这将是一个好主意,允许多个同时连接,由
将每个连接路由到线程
。但是,生成/销毁线程需要很长时间,因此建议拥有一个最初设置为“未使用”的线程“池”,并将每个连接传递给一个“当前未使用”的线程,在线程返回时将该线程标记为“正在使用”后,再次将其标记为“未使用”
在下面的代码中,没有做出任何努力来允许多个同时连接
for(;;)
{
addr = malloc(sizeof(struct sockaddr));
if( !addr )
{
perror( "malloc failed" );
exit( EXIT_FAILURE ); // exit() and EXIT_FAILURE from stdlib.h
}
// implied else, malloc successful
addrlen = sizeof( struct sockaddr );
int child_fd = accept(accept_fd, addr, &addrlen);
if( -1 == child_fd )
{ // then an error occurred
perror( "accept failed" );
}
else
{ // else, accept successful
printf("addr->sa_family = %d\n", addr->sa_family);
close(child_fd);
}
free( addr ); // to avoid memory leak
addr = NULL; // for safety
}
在调用accept
之前,必须初始化addrlen
。还有,为什么要动态分配?这可能只会导致内存泄漏(就像您现在所做的那样)。当调用任何内存分配函数(malloc、calloc、realloc)时,1)不要强制转换返回值。返回的值具有类型void*
,因此可以分配给任何指针。强制转换只会使代码变得混乱,使理解、调试和维护变得更加困难。2) 始终检查(!=NULL)返回值以确保操作成功。注意:始终将从内存分配返回的指针传递给函数free()
,以避免内存泄漏(在当前情况下,最终会导致系统崩溃),建议在调用close
后立即调用free()
,您对内存泄漏的看法是正确的;这段代码是从一个大得多的程序中复制的,该程序稍后将释放内存。在示例中,为了将来更清晰,我已经解决了这个问题。一个小问题:变量addrlen
需要在每次调用accept()
之前重新初始化,因为调用修改了value@user3629249:真的!谢谢。我想你弄错了-(-1=child\u fd)
应该有=
我对这个答案投了更高的票,因为它是唯一一个在中分配sockaddr\u而不是sockaddr
来调用accept()
的答案。由于侦听套接字是AF\u INET
,因此必须使用sockaddr\u in
。请注意,实际上不需要调用malloc()
和free()
,因为实际上只需要addr
变量的一个实例。
for(;;)
{
addr = malloc(sizeof(struct sockaddr));
if( !addr )
{
perror( "malloc failed" );
exit( EXIT_FAILURE ); // exit() and EXIT_FAILURE from stdlib.h
}
// implied else, malloc successful
addrlen = sizeof( struct sockaddr );
int child_fd = accept(accept_fd, addr, &addrlen);
if( -1 == child_fd )
{ // then an error occurred
perror( "accept failed" );
}
else
{ // else, accept successful
printf("addr->sa_family = %d\n", addr->sa_family);
close(child_fd);
}
free( addr ); // to avoid memory leak
addr = NULL; // for safety
}