2017-02-12 49 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進行測試。

相關問題