0

我正在 Unix 系统上用 C 语言编写客户端-服务器 (TCP) 程序。客户端发送一些信息,服务器回答。每个子进程只有一个连接。新连接使用池中的预运行进程,并且池大小是动态的,因此如果空闲进程(不为客户端提供服务的进程)的数量下降得太少,它应该创建新进程,同样如果它变得太高额外应该终止进程。

这是我的服务器代码。每个连接都使用fork(). 每个连接都在一个新进程中运行。我怎样才能像上面解释的那样制作一个动态池?

int main(int argc, char * argv[])
{
        int cfd;
        int listener = socket(AF_INET, SOCK_STREAM, 0); //create listener socket 
        if(listener < 0){
            perror("socket error");
            return 1;
        }
        struct sockaddr_in addr;
        addr.sin_family = AF_INET;
        addr.sin_port = htons(PORT);
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
        int binding = bind(listener, (struct sockaddr *)&addr, sizeof(addr));
        if(binding < 0){
            perror("binding error");
            return 1;
        }
        listen(listener, 1); //listen for new clients
        signal(SIGCHLD,handler);
        int pid;

        for(;;) // infinity loop on server
        {
            cfd = accept(listener, NULL, NULL); //client socket descriptor
            pid = fork(); //make child proc
            if(pid == 0) //in child proc...
            {
                close(listener); //close listener socket descriptor
                ... //some server actions that I do.(receive or send) 
                close(cfd); // close client fd
                return 0;
            }
            close(cfd);

}

4

1 回答 1

1

如果您在accept同一个侦听套接字上阻塞了多个进程,那么进来的新连接将被传递给其中一个。(视情况而定,可能会唤醒几个,但实际上只有一个会获得连接)。所以你需要 fork 几个孩子之后listen,但之前accept。处理请求后,孩子返回accept而不是exit. 处理(1)和(2)。

(3) 更难。您需要某种形式的 IPC。通常,您会有一个父进程来管理拥有正确数量的子进程。您的子进程需要使用 IPC 来告诉父进程他们有多忙。然后父母可以派生更多的孩子(进入accept上面的循环)或向孩子发送信号告诉他们完成并退出。它还应该处理wait儿童,处理意外死亡等。

您要使用的 IPC 可能是共享内存。您的两个选项是 SysV ( shmget) and POSIX (shm_open`) 共享内存。如果可用,您可能想要后者。您将不得不处理同步访问(POSIX 和 SysV 都提供信号量来帮助解决这个问题,同样更喜欢 POSIX)或仅使用原子访问。

(您可能实际上并不希望进程在有超过 X 个空闲子节点时立即退出,这将导致反复收获和生成它们,这很昂贵。相反,您可能希望了解它们在最后一秒......所以你的数据比使用/空闲的位图更复杂。)

有很多像这样工作的守护进程,所以你可以很容易地找到代码示例。当然,如果你去看看 Apache,你可能会发现它更复杂,要获得良好的性能和随处可移植。

于 2013-04-29T18:58:41.800 回答