【问题标题】:Why doesn't accept() block?为什么不接受()阻止?
【发布时间】:2013-01-08 15:19:25
【问题描述】:

我是 Linux (UNIX) 套接字下的套接字编程新手。 我在 Internet 上找到了以下代码,用于为每个连接生成一个线程的 tcp 服务器。 但是它不起作用。 accept() 函数立即返回,并且不等待连接。 我做错了什么?

这是代码

int main(int argv, char *args[])
{
    struct sockaddr_in addr;
    int sd, port;

    port = htons(SERVER_PORT);

    /*--- create socket ---*/
    sd = socket(PF_INET, SOCK_STREAM, 0);
    if ( sd < 0 )
        panic("socket");

    /*--- bind port/address to socket ---*/
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = port;
    addr.sin_addr.s_addr = INADDR_ANY;                   /* any interface */
    if ( bind(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
        panic("bind");

    /*--- make into listener with 10 slots ---*/
    if ( listen(sd, 10) != 0 )
        panic("listen")

    /*--- begin waiting for connections ---*/
    else
    {   int sd;
        pthread_t child;
        FILE *fp;

        while (1)                         /* process all incoming clients */
        {
            sd = accept(sd, 0, 0);     /* accept connection */
            fp = fdopen(sd, "wr+");           /* convert into FILE* */
            pthread_create(&child, 0, servlet, fp);       /* start thread */
            pthread_detach(child);                      /* don't track it */
        }
    }
} 

【问题讨论】:

  • 你没有检查accept的返回值,如果是-1你没有检查errno
  • 好吧,吸取教训,不要相信你从网站下载的代码。甚至示例也经常失败!
  • 很好,但不要忘记选择正确的答案。
  • 除了sd 的影子之外,对accept() 的调用会覆盖侦听套接字描述符。由于这将适用于对accept()一个 调用,因此它肯定不会在循环中工作(如OP 的代码sn-p 所示)。

标签: c linux sockets tcp


【解决方案1】:

您正在隐藏sd 变量,将无效的套接字传递给accept(),这会导致它立即失败。

它可能会返回EBADF 来表示错误的文件描述符。如果您检查代码中的返回值,您会注意到。

您应该启用更多编译器警告,以捕获此类内容。使用 GCC,您可以使用 @987654321@ 选项来启用此类警告。

【讨论】:

  • 不是别名,是阴影。别名意味着有一个变量指向与另一个相同的位置,因此不会出错。 :) 此外,编译器警告可能无济于事,因为这是完全有效的,不应在 GCC 中产生带有 -Wall 的警告。
  • 啊,你是对的,它既不是-Wall 的一部分,也不是-Wextra 的一部分。必须手动指定。
【解决方案2】:

您没有检查accept() 调用的返回值。它很可能会返回错误。

【讨论】:

  • 检查 unwind 的答案。无论如何,您必须在代码中包含该检查。
【解决方案3】:

有一个 sd 变量的重新定义

int sd;

【讨论】:

    【解决方案4】:

    一些问题:

    1) 你在 panic("listen") 上少了一个逗号

    2) 你声明了两次“sd”(一次在 main() 一次在 else)

    #include <stdio.h>
    #include <pthread.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netinet/ip.h>
    
    #define SERVER_PORT 30000
    
    int main(int argv, char *args[])
    {
        struct sockaddr_in addr;
        int sd, port;
    
        port = htons(SERVER_PORT);
    
        /*--- create socket ---*/
        sd = socket(PF_INET, SOCK_STREAM, 0);
    
        /*--- bind port/address to socket ---*/
        memset(&addr, 0, sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = port;
        addr.sin_addr.s_addr = INADDR_ANY;                   /* any interface */
    
        bind(sd, (struct sockaddr*)&addr, sizeof(addr));
    
        /*--- make into listener with 10 slots ---*/
        listen(sd, 10);
    
        /*--- begin waiting for connections ---*/
        pthread_t child;
        FILE *fp;
    
        while (1)                         /* process all incoming clients */
        {
            printf("before accept\n");
            sd = accept(sd, 0, 0);     /* accept connection */
            fp = fdopen(sd, "wr+");           /* convert into FILE* */
            //pthread_create(&child, 0, servlet, fp);       /* start thread */
            //pthread_detach(child);                      /* don't track it */
            printf("After accept\n");
        }
    
    } 
    

    【讨论】:

      【解决方案5】:

      它们是对变量 sd 的重新定义。

      int sd; // at line 3 and 26
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-09-09
        • 1970-01-01
        • 2021-11-11
        • 2015-01-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多