2016-09-27 74 views
0

我正在做一個小型的客戶端 - 服務器應用程序,其中服務器在接受之後分叉一個子進程,在客戶端連接到它時進行多個連接,發送消息並接收響應。以下是我的代碼片段: - client.c在TCP套接字連接期間通過對端重置連接?

char buffer [256];

portno=5001;  

    /* Create a socket point */ 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 

    if (sockfd < 0) { 
     perror("ERROR opening socket"); 
     exit(1); 
    } 


    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(portno); 

    /* Now connect to the server */ 
    if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { 
     perror("ERROR connecting"); 
     exit(1); 
    } 

    /* Now ask for a message from the user, this message 
     * will be read by server 
    */ 
while(1) 
{ 
    printf("Please enter the message: "); 
    bzero(buffer,256); 
    fgets(buffer,255,stdin); 
    /* Send message to the server */ 
    n = write(sockfd, buffer, strlen(buffer)); 

    if (n < 0) { 
     perror("ERROR writing to socket"); 
     exit(1); 
    } 

    /* Now read server response */ 
    bzero(buffer,256); 
    n = read(sockfd, buffer, 255); 
    if(n==0) 
    { 
     perror("nothing to read"); 
    } 

    if (n < 0) { 
     perror("ERROR reading from socket"); 
     exit(1); 
    } 

    printf("%s\n",buffer); 
} 

--server.c

int main(int argc, char *argv[]) { 
    int sockfd, newsockfd, portno, clilen; 
    char buffer[256]; 
    struct sockaddr_in serv_addr, cli_addr; 
    int n, pid; 

    /* First call to socket() function */ 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 

    if (sockfd < 0) { 
     perror("ERROR opening socket"); 
     exit(1); 
    } 

    /* Initialize socket structure */ 
    bzero((char *) &serv_addr, sizeof(serv_addr)); 
    portno = 5001; 

    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_addr.s_addr = INADDR_ANY; 
    serv_addr.sin_port = htons(portno); 

    /* Now bind the host address using bind() call.*/ 
    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { 
     perror("ERROR on binding"); 
     exit(1); 
    } 

    /* Now start listening for the clients, here 
     * process will go in sleep mode and will wait 
     * for the incoming connection 
    */ 

    listen(sockfd,5); 
    clilen = sizeof(cli_addr); 

    while (1) { 
     newsockfd = accept(sockfd, (struct sockaddr *)NULL,NULL); 

     if (newsockfd < 0) { 
     perror("ERROR on accept"); 
     exit(1); 
     } 

     /* Create child process */ 
     pid = fork(); 

     if (pid < 0) { 
     perror("ERROR on fork"); 
     exit(1); 
     } 



if (pid == 0) 
{ 
    while(1) 
    { 
    /* This is the client process */ 
    close(sockfd); 
    doprocessing(newsockfd); 
    /** exit(0); **/ 
    } 
} 
     else { 
     close(newsockfd); 
     } 

    } /* end of while */ 
} 


void doprocessing (int sock) { 
    int n; 
    char buffer[256]; 
    bzero(buffer,256); 
    n = read(sock,buffer,255); 
     if(n==0) 
    { 
     perror("nothing to read"); 
    } 

    if (n < 0) { 
     perror("ERROR reading from socket"); 
     exit(1); 
    } 

    printf("Here is the message: %s\n",buffer); 
    n = write(sock,"I got your message",18); 

    if (n <= 0) { 
     perror("ERROR writing to socket"); 
     exit(1); 
    } 

} 
當我運行兩個,O/P是繼

Please enter the message: arjun 
I got your message 
Please enter the message: gaur 
ERROR reading from socket: Connection reset by peer 

請help.how解決這個

+0

您還沒有關閉套接字在派生的子進程,你不檢查的recv的'()'零的返回值。 – EJP

+0

那麼接近(sockfd)裏面的子進程在幹什麼?我處理recv()= 0,但它不是打印裏面的語句。我編輯了代碼。 –

+0

'close(sockfd)'正在關閉偵聽套接字。分叉的孩子沒有關閉接受的套接字('newsockfd')。您不會在此分叉的子進程或客戶端中處理'n == 0',除非將其錯誤地視爲服務器的分叉子進程中的錯誤。 – EJP

回答

1

分叉的子進程正在退出而沒有關閉newsockfd。在一些導致連接重置而不是有序關閉的平臺上。

您還需要檢查recv()的結果爲零並正確處理,即不是錯誤,並且還需要正確使用正返回值,例如,而不是

printf("%s\n",buffer); 

應該

printf("%.*s\n",n,buffer); 
+0

如果我在退出(0)之前關閉newsockfd,那麼客戶端在發送第二組數據時如何第二次連接到服務器? –

+1

您剛剛在自己的應用程序協議中暴露了一個缺陷。服務器的分叉子進程處理單個請求並回復,然後退出,但客戶端希望能夠通過單個連接發送多個請求。客戶端需要丟失其循環,否則服務器上的分叉子進程需要使用一個進程。 – EJP

+0

第一次運行後,孩子將退出接收數據,打印它,寫入套接字(客戶端讀取和打印),關閉接受的套接字並退出。但是我想讓孩子繼續運行。e套接字不會關閉,直到客戶希望這樣做 –

-1

你客戶端是這樣做的:

  • 連接到服務器
  • 一些數據發送到服務器
  • 從服務器
  • 接收的一些數據的一些數據發送到服務器
  • 從服務器
  • ...
  • 接收的一些數據

但你的服務器(一次與多個連接可能)做到這一點:

  • 等待連接
  • 從客戶
  • 接受一些東西寄一些東西給客戶
  • 關閉連接(通過退出具有打開連接的唯一進程)

所以服務器在客戶端即將發送更多數據時關閉連接,並且由於服務器關閉了連接,客戶端會收到錯誤。

您需要讓服務器在一個循環中保持接收和發送數據(所以它可以在同一個連接上發生多次),或者讓客戶端在每次發送內容時都建立一個新的連接。

+0

我不認爲這是由於多個連接一次,因爲現在我只連接一個客戶端到服務器 –

+0

@arjungaur我沒有說這個問題是由於一次多個連接。再次閱讀。 – immibis

+0

是的,我讀過它,你說可能,這就是爲什麼我剛纔告訴你,確認我們可以取消那一個,並尋找其他連接關閉的原因。 –

1

會發生什麼事是:

  1. 服務器開始監聽。
  2. 客戶端連接到偵聽服務器。
  3. 服務器分叉進程服務客戶端。
  4. 客戶端發送數據。
  5. 服務過程從3.接收客戶的日期並打印它。
  6. 服務過程從3.發送響應到客戶端。
  7. 從3開始的服務進程存在/結束,並且接受的套接字(與客戶端的對等端)關閉。
  8. 客戶端收到響應並打印出來。
  9. 客戶端嘗試更多的數據發送給服務處理作爲3 ..
  10. 客戶端嘗試從服務過程的3讀更多的數據..
  11. 步驟10.失敗作爲3由於服務過程已經結束(第7步)
+0

感謝您的澄清,但是當我從7刪除該退出(0),並建立一個新的連接,即使第一個請求沒有得到處理,我得到「壞文件編號」,任何想法如何解決這個問題,所以只要客戶端已完成請求,子服務客戶端不會關閉已接受的套接字? –

+0

@arjungaur:將代碼放在'doprocessing()'裏面,直到滿足某個條件? – alk

+0

堆棧跟蹤顯示接收時發生錯誤,而不是發送時。 – EJP