简体   繁体   English

accept()调用不会初始化sockaddr结构

[英]accept() call doesn't initialize sockaddr struct

I have written a short TCP server example in C which continually listens for connections on port 12701, and outputs the value of the peer's sockaddr.sa_family to stdout. 我用C语言编写了一个简短的TCP服务器示例,该示例不断侦听端口12701上的连接,并将对等方的sockaddr.sa_family的值输出到stdout。 The program calls accept() in an infinite loop, which should fill in a struct sockaddr with the details of the connection, including sa_family. 程序在无限循环中调用accept(),该循环应在struct sockaddr填充连接的详细信息,包括sa_family。

However, this doesn't happen correctly for the first TCP connection; 但是,对于第一个TCP连接,这种情况不会正确发生。 sockaddr.sa_family is always zero. sockaddr.sa_family始终为零。 All subsequent connections provide a correct value of two - only the first one is wrong. 所有后续连接均提供正确的值2-仅第一个错误。 Why does this happen? 为什么会这样? I haven't been able to find any reports of similar problems, but I suspect I am initializing something incorrectly or misinterpreting the parameters of accept(). 我没有找到类似问题的任何报告,但我怀疑我在初始化某些错误或误解了accept()的参数。

Here is the program: 这是程序:

#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;
}

This assumes AF_INET for the connection to be setup. 假定使用AF_INET建立连接。

You want to pass to accept() the address of a structure suitable to what you bound the listening socket to, that is a struct sockaddr_in . 您想传递一个accept()结构体的地址,该结构体适合于将侦听套接字绑定到的struct sockaddr_in ,即struct sockaddr_in

Also addrlen needs to be set to the size of what the address of is passed to accept() . 另外,还需要将addrlen设置为传递给accept()的地址的大小。

  for (;;)
  {
    struct sockaddr_in * addr = malloc(sizeof *addr);
    socklen_t addrlen = sizeof *addr;

    if (NULL == addr)
    {
       perror("malloc() failed");
       /* exit(), break, continue, whatever ... */
    }

    int child_fd = accept(accept_fd, (struct sockaddr *) addr, &addrlen);
    if (-1 == child_fd)
    {
       perror("accept() failed");
       free(addr);
       addr = NULL;
       /* exit(), break, continue, whatever ... */
    }

    /* Do stuff. */

    close(child_fd);
    free(addr);
  }

the call to accept() is not being handled correctly. accept()的调用未正确处理。

in the posted code: 在发布的代码中:

  1. the call to accept() must be checked for a failure. 必须检查对accept()的调用是否失败。
  2. the call to malloc() must be checked for a failure 必须检查对malloc()的调用是否失败
  3. the allocated memory must be free'd 分配的内存必须被释放
  4. the addrlen parameter to accept() must be properly initialized before each call to accept() . 在每次调用accept()之前,必须正确初始化accept()addrlen参数。

The posted code can only handle one connection at a time. 发布的代码一次只能处理一个连接。 It would be a good idea to allow for multiple simultaneous connections by having each connection be routed to a thread . 通过将每个连接路由到一个thread来允许多个同时连接是一个好主意。 However, generating/destroying threads takes a long time, so suggest having a 'pool' of threads that are initially set to 'unused' and passing each connection to a 'currently unused' thread, after marking that thread as 'in use' When the thread returns, mark it as 'unused', again. 但是,生成/销毁线程会花费很长时间,因此建议将该线程标记为“使用中”后,先将其初始设置为“未使用”的线程“池”并将每个连接传递给“当前未使用”的线程。线程返回,再次将其标记为“未使用”。

In the following code, no effort has been made to allow for multiple simultaneous connections. 在以下代码中,没有做出允许同时进行多个连接的努力。

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
}

Take a look at for instance this documentation : http://man7.org/linux/man-pages/man2/accept.2.html 例如,看一下此文档: http : //man7.org/linux/man-pages/man2/accept.2.html

And more specifically the description of the addrlen parameter. 更具体地说,addrlen参数的描述。 This is an inout parameter and you must initialise it properly. 这是一个inout参数,您必须正确初始化它。

The addrlen argument is a value-result argument: the caller must initialize it to contain the size (in bytes) of the structure pointed to by addr; addrlen参数是一个值结果参数:调用者必须对其进行初始化,以包含addr指向的结构的大小(以字节为单位); on return it will contain the actual size of the peer address.' 返回时,它将包含对等地址的实际大小。”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM