为什么每次从客户端写入消息,该程序都要在C/ c++中创建一个新的进程

Why for each write message from client this program make a new process in C/C++?

本文关键字:创建 c++ 进程 一个 客户端 消息 程序 为什么      更新时间:2023-10-16

我正在尝试设计一个具有并发功能的回声服务器。这意味着,服务器为每个客户端创建父进程和子进程。它是一个游戏服务器和每个客户端分别玩。我已经提出了以下代码,但我不知道为什么每次有从客户端到服务器的消息,它开始创建一个新的进程,并从

for(;;){ // Run forever开始。

正如我所说的,我认为我必须为每个客户端设置一个进程。我希望每个进程都保持在HandleTCPClient,直到客户端关闭其套接字

另一个问题是,我可以在哪里初始化我的数据,以便每个子进程与自己共享它。

#include "wrappers.h"   // socket wrapper fns
#include <sys/wait.h>   // for waitpid()
#define RCVBUFSIZE 32   // Size of receive buffer
void HandleTCPClient(int ClntSocket);
extern "C" void SigChldHandler( int Signum );
int i = 0;
int main(int argc, char *argv[])
{
    int ServSock;                    // Socket descriptor for server
    int ClntSock;                    // Socket descriptor for client
    unsigned short EchoServPort;     // Server port
    sockaddr_in EchoServAddr;        // Local address
    sockaddr_in EchoClntAddr;        // Client address
    pid_t ProcessID;                 // Process ID from fork()
    unsigned int ChildProcCount = 0; // Number of child processes

    EchoServPort = SERV_TCP_PORT;;  // First arg:  local port
    // Create socket for incoming connections
    ServSock = Socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    // Construct local address structure
    memset((char*)&EchoServAddr, 0, sizeof(EchoServAddr));   /* Zero out structure */
    EchoServAddr.sin_family = AF_INET;                /* Internet address family */
    EchoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */
    EchoServAddr.sin_port = htons(EchoServPort);              /* Local port */
    // Bind to the local address
    Bind(ServSock, (sockaddr*)&EchoServAddr, sizeof(EchoServAddr));
    // Mark the socket so it will listen for incoming connections
    Listen(ServSock, 5);
    signal(SIGCHLD, SigChldHandler); // for preventing zombies
    for(;;){ // Run forever
        // Set the size of the in-out parameter
        socklen_t ClntLen = sizeof(EchoClntAddr);
        // Wait for a client to connect
        ClntSock = Accept(ServSock, (sockaddr*) &EchoClntAddr,&ClntLen);

        //Startin point of new new player to server

        // ClntSock is connected to a client!
        printf("Handling client %sn", inet_ntoa(EchoClntAddr.sin_addr));
        // Fork child process and report any errors
        if ((ProcessID = fork()) < 0){
            perror("fork() failed");
            exit(1);
        }
        if (ProcessID == 0){   // If this is the child process
            close(ServSock);   // Child closes (deallocates) its parent socket descriptor
            HandleTCPClient(ClntSock);
            exit(1);           // Child process terminates
        }
        printf("With child process: %dn", (int)ProcessID);
        close(ClntSock);       // Parent closes (deallocates) its child socket descriptor
        ChildProcCount++;      // Increment number of outstanding child processes
    }
    // NOT REACHED
}
void HandleTCPClient(int ClntSocket){
    i++;
    cout<<"Start of handling"<<endl;
    cout<<"i="<<i<<endl;
    char EchoBuffer[RCVBUFSIZE];        // Buffer for echo string
    int RecvMsgSize;                    // Size of received message
    // Receive message from client
    if((RecvMsgSize = recv(ClntSocket, EchoBuffer, RCVBUFSIZE, 0)) < 0){
        perror("recv() failed"); exit(1);
        cout<<"Error"<<endl;
    }
    // Send received string and receive again until end of transmission
    while(RecvMsgSize > 0){ // zero indicates end of transmission
        // Echo message back to client
        if(send(ClntSocket, EchoBuffer, RecvMsgSize, 0) != RecvMsgSize){
            cout<<"Error"<<endl;
            perror("send() failed"); exit(1);
        }
        // See if there is more data to receive
        if((RecvMsgSize = recv(ClntSocket, EchoBuffer, RCVBUFSIZE, 0)) < 0){
            cout<<"Error"<<endl;
            perror("recv() failed"); exit(1);
        }
    }
    close(ClntSocket);    /* Close client socket */
    cout<<"End of handling"<<endl;
}

extern "C" void SigChldHandler( int Signum ){
// Catch SIGCHLD signals so child processes don't become zombies.
    pid_t pid;
    int stat;
    while((pid = waitpid(-1, &stat, WNOHANG)) > 0 );
    return;
}

客户端到服务器的三条消息输出:

Handling client 127.0.0.1
With child process: 40830
Start of handling
i=1
Handling client 127.0.0.1
With child process: 40831
Start of handling
i=1
Handling client 127.0.0.1
With child process: 40832
Start of handling
i=1
Handling client 127.0.0.1
With child process: 40833
Start of handling
i=1
End of handling
End of handling
End of handling
End of handling

正如你所看到的,它创建了三个进程,当我关闭程序时,它将为每个进程关闭socket !!

> Edit2客户端抽象:

int main()
{
  int Sockfd;
  sockaddr_in ServAddr;
  char ServHost[] = "localhost";
  hostent *HostPtr;
  int Port = SERV_TCP_PORT;
  //int BuffSize = 0;
  //Connection
  // get the address of the host
  HostPtr = Gethostbyname(ServHost);
  if(HostPtr->h_addrtype !=  AF_INET){
     perror("Unknown address type!");
     exit(1);
  }
  memset((char *) &ServAddr, 0, sizeof(ServAddr));
  ServAddr.sin_family = AF_INET;
  ServAddr.sin_addr.s_addr = ((in_addr*)HostPtr->h_addr_list[0])->s_addr;
  ServAddr.sin_port = htons(Port);
//Do some operation
  while(!loop){
      // open a TCP socket
      Sockfd = Socket(AF_INET, SOCK_STREAM, 0);
      // connect to the server
      Connect(Sockfd, (sockaddr*)&ServAddr, sizeof(ServAddr));

//Prepare message to send server

       // write a message to the server
       write(Sockfd, data, sizeof(data));
           int Len = read(Sockfd, data, 522);

//work on the message from server
     }
     close(Sockfd);
}

您的客户端正在创建一个新的套接字并在每次写/读之前连接它,而不是多次使用已经连接的套接字。客户端应该创建一个套接字,将其连接到服务器,然后根据需要执行尽可能多的写/读操作,而不需要创建新的连接。

服务器正确地将每个新连接视为新客户端,并分叉来处理它。

关于在分叉进程之间共享数据,您可以使用如下所述的共享内存。

客户端每写一条消息都调用socketconnect

while (...) {
    socket(...);
    connect(...); /* here the server forks a new child process */
    write(...);
}

如果想避免这种情况,必须将连接移到循环

之前。
socket(...);
connect(...); /* here the server forks a new child process */
while (...) {
    write(...);
}