首页 > 代码库 > Socket编程实践(8)

Socket编程实践(8)

服务端多进程避免僵尸进程的方法

1)通过忽略SIGCHLD信号,解决僵尸进程

    在server端代码中添加

signal(SIGCHLD, SIG_IGN);

2)通过wait/waitpid方法,解决僵尸进程

  signal(SIGCHLD,onSignalCatch);
  
  void onSignalCatch(int signalNumber)
  {
      wait(NULL);
  }

Server端部分代码:

//return a socket that have start listened.
int mkATCPServer(int serverPort, int backlog = SOMAXCONN)
{
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if (sockfd == -1)
    {
        err_exit("socket error");
    }

    //add address reused
    int on = 1;
    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) == -1)
    {
        err_exit("setsockopt SO_REUSEADDR error");
    }

    //band a local address and port
    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(serverPort);
    serverAddr.sin_addr.s_addr = INADDR_ANY;    //band an any IP address
    if (bind(sockfd,(struct sockaddr *)&serverAddr,sizeof(serverAddr)) == -1)
    {
        err_exit("bind error");
    }

    //start to listen.
    if (listen(sockfd,backlog) == -1)
    {
        err_exit("listen error");
    }

    return sockfd;
}

void onSignalCatch(int signalNumber)
{
    waitpid(-1,NULL,WNOHANG);
}

int main()
{
  //安装SIGCHLD信号处理函数
    signal(SIGCHLD,onSignalCatch);
    int serverSockfd = mkATCPServer(8002);

    struct sockaddr_in peerAddr;
    socklen_t peerLen = sizeof(peerAddr);

    while (true)
    {
        //接受链接
        int peerSockfd = accept(serverSockfd, (struct sockaddr *)&peerAddr,&peerLen);
        if (peerSockfd == -1)
        {
            err_exit("accept error");
        }
.....
//其他部分代码与前面相似

多客户端同时关闭问题

问题描述如下:



客户端代码实现代码

//其他代码如前
//....
int main()
{
    int serverSocket[10];
    int socketCount = 10;
    for (int i = 0; i < socketCount; ++i)
    {
        serverSocket[i] = mkATCPClient(8002,"127.0.0.1");
    }

    sleep(100);

    return 0;
}

 在客户运行过程中按下Ctrl+C,则可以看到在server端启动10个子进程,并且所有的客户端全部一起断开的情况下,产生的僵尸进程数是惊人的(此时也证明了SIGCHLD信号是不可靠的)!

 

 

解决方法:

//server端部分代码如下:
//其他如前....
void onSignalCatch(int signalNumber)
{
  int ret = 0;
  //注意此处!!!!
    while ((ret = waitpid(-1,NULL,WNOHANG) != -1))
        ;
}

int main()
{
    signal(SIGCHLD,onSignalCatch);
    int serverSockfd = mkATCPServer(8002);
  ...

从下图可以看出,出了监听server进程,已经没有僵尸进程了!



Socket编程实践(8)