2016-09-27 72 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