我在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);
}
答案 0 :(得分:1)
如果您在同一个侦听套接字上的accept
中阻止了多个进程,则进入的新连接将传递给其中一个进程。 (取决于,有几个人可能会醒来,但实际上只有一个人会获得连接)。所以你需要在listen
之后但在accept
之前分叉几个孩子。处理完请求后,孩子会返回accept
而不是exit
。处理(1)和(2)。
(3)更难。你需要某种形式的IPC。通常,您有一个父进程,只管理具有正确数量的子进程。您的子进程需要使用IPC告诉父母他们有多忙。然后父母可以分叉更多的孩子(进入上面的accept
循环)或向孩子发送信号告诉他们完成并退出。它还应该处理wait
对孩子的处理,处理意外的死亡等等。
您要使用的IPC可能是共享内存。您的两个选项是SysV(shmget) and POSIX (
shm_open`)共享内存。你可能想要后者(如果有的话)。您将不得不处理同步访问(POSIX和SysV都提供信号量来帮助解决此问题,再次使用POSIX)或仅使用原子访问。
(你可能实际上并不希望一个进程退出瞬间有超过X个免费的孩子,这将导致反复收割并产生它们,这是昂贵的。相反,你可能想要一些衡量他们如何利用他们超过最后一秒......所以你的数据比使用/免费的位图更复杂。)
有很多守护进程都是这样工作的,所以你可以很容易地找到代码示例。当然,如果你去看看Apache,你可能会发现它更复杂,要获得良好的性能并且随处可移植。