为什么accept()不会阻塞?

4
我是一名能翻译文本的助手。
我在Linux(UNIX)套接字下进行socket编程比较新。我在网上找到了以下代码,用于为每个连接生成一个线程的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 */
        }
    }
} 

2
你没有检查accept的返回值,如果它是-1,你也没有检查errno - Jonathan Wakely
可能是 http://stackoverflow.com/questions/4005067/c-failing-at-socket-accept-method 的重复问题。 - m0skit0
1
好的,教训已经吸取了,不要相信从网站下载的代码。即使是示例也经常会失败! - stdcall
好的,但别忘了选择正确的答案。 - m0skit0
除了“sd”的遮蔽,对“accept()”的调用将覆盖监听套接字描述符。虽然这对于一次“accept()”调用可以工作,但在循环中(如OP的代码片段所示)肯定无法工作。 - alk
5个回答

5

你在追踪sd变量时,向accept()传递了一个无效的套接字,导致它立即失败。

它很可能会返回EBADF来表示坏的文件描述符。如果你在代码中检查了返回值,就会注意到这一点。

你应该启用更多的编译器警告,以捕获这类问题。使用GCC,你可以使用-Wshadow选项来启用此类警告。


3
这不是别名问题,而是遮蔽问题。别名问题意味着一个变量指向与另一个变量相同的位置,因此不会产生错误。:) 此外,编译器警告可能不会有所帮助,因为这是完全有效的,并且在GCC中使用“-Wall”不应该产生警告。 - netcoder
2
啊,你说得对,它既不是-Wall的一部分,也不是-Wextra的一部分。必须手动指定。 - netcoder

2

你没有检查accept()调用的返回值。很可能它正在返回一个错误。


检查unwind的答案。无论如何,您必须在您的代码中包含该检查。 - m0skit0

2

sd变量被重新定义了。

int sd;

0
一些问题:
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");
    }

} 

0

变量sd被重新定义了。

int sd; // at line 3 and 26

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接