2016-12-07 48 views
2

我想創建兩個程序的客戶端和服務器,其中客戶端打開套接字連接,然後寫入數據到服務器誰接受連接產生一個新的線程,然後分離它,處理其餘的讀/寫道。問題在於,當我進行多次寫入時,從客戶端讀取的讀取沒有得到正確的數據,但是在服務器端,它會打印它發送正確的數據。使用線程來處理來自套接字的多個讀取/寫入?

這是我的代碼看起來像生成新線程,以及我如何處理這些線程。

while(1){ 
    listen(sockfd,5); 

    // determine the size of a clientAddressInfo struct 
    clilen = sizeof(clientAddressInfo); 
    int *newsockfd = malloc(sizeof(int)); 
    // block until a client connects, when it does, create a client socket 
    *newsockfd = accept(sockfd, (struct sockaddr *) &clientAddressInfo, &clilen); 
    // if the connection blew up for some reason, complain and exit 
    if (*newsockfd < 0){ 
     error("ERROR on accept"); 
    } 
    connection_args *args = malloc(sizeof(connection_args)); 
    args->file_descrp = newsockfd; 
    pthread_t tid; 
    pthread_create(&tid,NULL, handle_connect, args); 
} 

void * handle_connect(void* args){ 
    connection_args* connect_arg = (connection_args*)args; 
    pthread_detach(pthread_self()); 
    int n = -1; 
    char buffer[256]; 
    bzero(buffer,256); 
    //while not close; 
    while(1){ 
     // try to read from the client socket 
     n = read(*connect_arg->file_descrp,buffer,255); 
     printf("input: %s\n", buffer); 
     // if the read from the client blew up, complain and exit 
     if (n < 0){ 
      error("ERROR reading from socket"); 
     } 
     int fd; 
     if(strcmp("open",buffer) == 0){ 
      fd = open("file.txt",0); 
      bzero(buffer,256);  
      sprintf(buffer,"%d",fd); 
     }else if(strcmp("read",buffer) == 0){ 
      char *read_buffer = malloc(sizeof(char)*256); 
      bzero(read_buffer,256); 
      fd = read(get_filedescrp(),read_buffer,30); 
      bzero(buffer,256); 
      sprintf(buffer,"%s,%d",read_buffer,fd); 

     }else if(strcmp("close",buffer) == 0){ 
      break; 
     } 
     printf("buffer_send: %s\n",buffer); 
     // try to write to the client socket 
     n = write(*connect_arg->file_descrp,buffer,sizeof(buffer)); 
     // if the write to the client below up, complain and exit 
     if (n < 0){ 
      printf("here!!\n"); 
      error("ERROR writing to socket"); 
     } 
     bzero(buffer,256); 
    } 
    printf("Left thread\n"); 
    return NULL; 
} 
+1

就在一般情況下,我推薦使用Wireshark和[Netcat](https://linux.die.net/man/1/nc)來調試網絡代碼。 Wireshark當然會讓你看到你發送的內容,並且你可以使用'nc'作爲一個已知的服務器和客戶端,這樣你就可以隔離你的服務器和客戶端,從而減少你一次執行的變量數量。 – yano

+1

不要在'accept()'循環中調用'listen()'。在進入循環之前調用它一次。並且不需要'malloc()'你的套接字描述符。並且,在執行以null結尾的操作之前,您不是空終止您的「緩衝區」,如'printf()'和'strcmp()'。你也沒有考慮到TCP是一個流式傳輸,並不能保證'read()'會接收完整的字符串,它可以(也可能)有時會接收部分數據。您需要在發送端分隔您的命令,並在讀取端查找這些分隔符。 –

+0

在客戶端調用read()兩次,然後獲取正確的數據。我如何說明TCP是一個流式傳輸,在我得到一個非空響應之前一直調用read()?關於空終止字符,如果一個字符串與空終止字符一起發送,我需要手動重新添加它後,我讀? – user1457388

回答

1

如果沒有某種協議,您無法通過TCP/IP實現客戶端服務器通信。發件人寫入的數據可以沿着方向切片和切塊,並以不同的塊長度傳送給讀者端。在嘗試解釋數據之前,您必須有辦法告訴您是否已收到全幀。例如,您可以使用一個非常簡單的基於行的協議:讀取數據,幷包括'\n'字節。一次讀取一個字節到一個留置緩衝區中效率不高,但容易實現。

1

套接字讀取調用可能會或可能不會在單次調用中返回客戶端發送的整個數據。 每個讀取調用返回的字節數是在該調用中讀取的字節數。所以應用程序應該循環讀取,直到讀取預期的字節數。