accept()调用不';t初始化sockaddr结构

accept()调用不';t初始化sockaddr结构,c,sockets,unix,C,Sockets,Unix,我用C编写了一个简短的TCP服务器示例,它持续侦听端口12701上的连接,并将对等方的sockaddr.sa_族的值输出到stdout。程序在无限循环中调用accept(),该循环应在struct sockaddr中填充连接的详细信息,包括sau族 但是,对于第一个TCP连接,这种情况不会正确发生;sockaddr.sau族始终为零。所有后续连接都提供了正确的值2-只有第一个连接是错误的。为什么会发生这种情况?我还没有找到任何类似问题的报告,但我怀疑我初始化了错误的内容或误解了accept()的

我用C编写了一个简短的TCP服务器示例,它持续侦听端口12701上的连接,并将对等方的sockaddr.sa_族的值输出到stdout。程序在无限循环中调用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
    }