2017-02-12 50 views
0

我一直在用C编写一个使用unix套接字和pthreads的小型多线程TCP服务器,但是我遇到了accept()的问题。它会挂起第二个请求,并且只有在先前线程退出时才会取消阻止。具有C套接字和pthreads的多线程TCP服务器 - 为什么accept()阻塞第二个请求?

下面是如何设置服务器套接字。

int server_start(server_t *server, int port) { 
    int fd; 
    struct sockaddr_in server_addr; 

    // Socket file descriptor. 
    fd = socket(AF_INET, SOCK_STREAM, 0); 
    if (fd == -1) { 
     perror("socket failed"); 
     return 1; 
    } 

    // Socket address. 
    server_addr.sin_family  = AF_INET; 
    server_addr.sin_addr.s_addr = INADDR_ANY; 
    server_addr.sin_port  = htons(port); 

    // Bind. 
    if (bind(fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1) { 
     perror("bind failed"); 
     return 1; 
    } 

    server->fd = fd; 
    listen(server->fd, server->clients_len); 
    pthread_create(&(server->thread), NULL, thread_entry_server, server); 

    return 0; 
} 

这是我的add_client代码。它为客户产生了一个单独的线程。

client_t *server_add_client(server_t *server) { 

    int iter, 
     fd, 
     status; 
    client_t *client; 

    printf("before\n"); 
    fd = accept(server->fd, NULL, 0); 
    printf("after\n"); 

    if (fd == -1) { 
     perror("accept"); 
     return NULL; // Connection failed. 
    } 

    // Find an empty spot. 
    client = server->get_empty_spot(); 
    client->fd = fd; 

    // Start the new thread. 
    status = pthread_create(
     &(client->thread), 
     NULL, 
     thread_entry_client, 
     client 
    ); 
    if (status != 0) { 
     perror("pthread_create"); 
     close(client->fd); 
     return NULL; 
    } 

    client->active = 1; 

    return client; 
} 

这是我的客户端线程的入口函数:

void *thread_entry_client(void *void_client) { 

    client_t *client = void_client; 
    int len; 

    while (1) { 

     len = recv(client->fd, client->recv_buffer, RECV_BUFFER_LEN, 0); 
     if (len < 0) { 
      perror("recv"); 
      client->active = 0; 
      close(client->fd); 
      return NULL; 
     } 
     if (len == 0) { // Client disconnected. 
      client->active = 0; 
      close(client->fd); 
      printf("disconnect\n"); 
      return NULL; 
     } 

     if (len > 0) { 
      //printf("%s\n", client->recv_buffer); 
      printf("msg\n"); 
     } 
    } 

    return NULL; 
} 

所以我在做什么测试,这是建立两个连接。第一个连接通过并且工作正常,但第二个连接不是 - 而是线程挂在accept()上。我知道这是从我的printfs(我留在那里)得知的,我知道在第一个客户端断开连接之后,accept()解除阻塞。我也知道我的代码没有关闭服务器套接字文件描述符或改变它。

上调试这有什么建议?我无法弄清楚。

编辑:这里是thread_entry_server。

void *thread_entry_server(void *void_server) { 
    server_t *server = void_server; 
    client_t *client; 

    while (1) { 
     client = server_add_client(server); 
     if (client == NULL) // Server is full or connection failed. 
      continue; 
    } 

    return NULL; 
} 
+0

不应该'在pthread_create()''传递的server_add_client'代替'thread_entry_server'? – alk

+0

哎呀,我忘了包含thread_entry_server。我会添加它。 –

+0

在接收到传入的TCP连接之前,accept()将不会返回; connect()到accept()正在监听的端口是什么? –

回答

0

这是因为accept()将阻止(除非另有配置),直到客户端连接是可用的。

Documentation其中提到 -

如果听队列为空连接请求和O_NONBLOCK是 上套接字的文件描述符没有设置,accept()方法将阻止 直到连接存在。如果听()队列为空 连接请求和O_NONBLOCK为 插座设置的文件描述符,accept()方法将失败,errno设置为[EAGAIN]或 [EWOULDBLOCK]。

此外,server->get_empty_spot();应该总是返回新client情况下,否则这将意味着要传递相同client->threadpthread_create

我通常喜欢创建新的线程自己,像 -

**pthread_t newListner;** 
ThreadArgs thread_args; 
thread_args.client_socket = client_socket; 

int rc; 

if ((rc = pthread_create(&newListner, NULL, startListener, &thread_args))) 
{ .. } 

试试看吧。

+0

我意识到这一点,那就是我想要的行为。问题是,当我再次连接(第一个连接仍然打开)时,接受继续阻止。它只在第一个客户端断开连接时才会解除阻塞。 –

+0

我应该在我的文章中更清楚地更新它。 –

0

我用JavaScript的WebSocket的测试,但我没有做任何握手所以它没有完成连接。使用telnet进行测试。

相关问题