C 中具有多个进程的 TCP Echo 服务器

TCP Echo Server with multiple processes in C

我正在尝试编写一个 TCP 回显服务器,它为每个连接创建一个新进程。但不知何故,它没有按预期工作。

    #include <stdlib.h>      // use common functions
#include <stdio.h>       // use input/output functions
#include <string.h>      // use string functions
#include <unistd.h>      // use POSIX functions

#include <sys/socket.h>  // use socket function
#include <netinet/in.h>  // use internet address datatypes
#include <arpa/inet.h>   // use inet_ntoa function

/** A simple server application in the internet domain using TCP.
    The port number is passed as an argument to the program.
*/

#include <netdb.h>
#include <sys/wait.h>

void doprocessing (int sock);

int main( int argc, char *argv[] ) {
   int sockfd, newsockfd, clilen, status;
   struct sockaddr_in serv_addr, cli_addr;
   int pid;
   
   // Read parameters
    if (argc < 2) {
        printf("Usage: TPCServer <port>\n");
        return -1;
    }
    
    int port = atoi(argv[1]);
   
   /* 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));
   
   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(port);
   
   /* 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 (newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, (socklen_t *) &clilen)) {
        
      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) {
         char buffer[256];
          
         /* This is the client process */
         close(sockfd);
         
         while(recv(newsockfd, buffer, 100, 0)>0){
            int n;
            
            
            bzero(buffer,256);
            n = read(newsockfd,buffer,255);
   
            if (n < 0) {
                perror("ERROR reading from socket");
                exit(1);
            }
   
            printf("%s\n",buffer);
            n = write(newsockfd,buffer,18);
   
            if (n < 0) {
                perror("ERROR writing to socket");
                exit(1);
            }
            //newsockfd = accept(newsockfd, (struct sockaddr *) &cli_addr, (socklen_t *) &clilen);
         }
         exit(0);
      }
      else {
         /* This is the parent process */ 
         close(newsockfd);
         waitpid(pid, &status, WNOHANG);
      }
        
   } /* end of while */
}

当我应该得到“foo42bar”时,我却得到了“bar����������������”。我认为问题在于保持连接。所以我希望这里有错误:

if (pid == 0) {
         char buffer[256];

         /* This is the client process */
         close(sockfd);

         while(recv(newsockfd, buffer, 100, 0)>0){
            int n;


            bzero(buffer,256);
            n = read(newsockfd,buffer,255);

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

            printf("%s\n",buffer);
            n = write(newsockfd,buffer,18);

            if (n < 0) {
                perror("ERROR writing to socket");
                exit(1);
            }
            //newsockfd = accept(newsockfd, (struct sockaddr *) &cli_addr, (socklen_t *) &clilen);
         }
         exit(0);
      }

感谢您的帮助。

您有两个问题:

n = read(newsockfd,buffer,255);之后,变量n保存读取的字节数。那就是你应该打印的字节数和你应该写入的字节数。但是在您随后的打印和发送代码中,您没有使用 n 的值,因此您发送或打印的字符多于收到的字符,导致您看到垃圾。

由于您将缓冲区清零,因此您的打印可能会成功。尽管如果接收到的数据恰好包含零字节,那将会失败。但是对 write 的调用总是 发送 18 个字节,这可能太多或太少。

此外,出于某种原因,您在 while 循环中调用了 recv 并丢弃了结果。这将导致数据丢失。不要调用 recv 然后调用 read。选择一个使用,不要丢弃结果,因为那是您要回显的数据。