2013-04-28 65 views
1

我在C上的UNIX上编写程序,我必须在套接字上编写客户端 - 服务器(TCP)程序。客户端发送一些信息和服务器答案。不管客户端发送或接收的是什么,因为我成功地为它写了代码。但是任务的最后部分对我来说非常困难。进程的动态池C

1)一个连接 - 一个子进程。

2)对于使用运行前处理从池中的新连接。

3)池的大小是dinamic.If(不服务客户)免费进程的数量大于N变得不那么 - 应创建新的进程,如果它于K变得更加 - “额外”的进程必须被终止。

这是我的代码。每个连接都使用fork()进行新的子进程。每个连接都以新进程运行。但是如何制作我上面所说的动态池呢?
请帮忙,这非常重要!这是我应该做的最后一件事。

服务器代码:

int main(int argc, char * argv[]) 
{ 
     int cfd; 
     int listener = socket(AF_INET, SOCK_STREAM, 0); //create listiner 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); 
     } 

     return 0; 
} 
+0

所以,你需要父和池中的孩子之间的某种IPC。你有什么指导什么IPC机制使用? 'socketpair'也许? – hyde 2013-04-28 20:57:15

+0

我昨天读过这本书,意在回到它。这比普通的学生项目要复杂一些。 – Duck 2013-04-29 20:20:38

回答

3

这是一个设计或体系结构问题,对代码的权威性回答太宽泛。

所以,你知道你想在自己的过程中服务每个新的连接。您的其他两个约束构成(至少)两个问题:

首先,是怎样一个新的连接路由到N已经在运行一个工人?

这是比较容易的。这里最常见的设计是:

  • 每个工人继承了监听套接字和执行自己的接受()
    工人可能互斥监听套接字,所以只有一个准备调用accept()在任何给定的时间,或者他们可能只是简单地调用accept() - 但在这种情况下,请注意the thundering herd
  • 工人得到已经接受来自某些其它过程经由UNIX文件描述符传递()的连接。
    例如,参见SO question

其次,我们如何确保ñ - ķ空闲的可用工作进程?

这是一个更大的问题,你必须根据你的舒适度和其他约束来回答。

您需要知道,不仅有多少工人活着,而且哪些工人闲着(“免费”)。让父母的流程跟踪其子女是一个明显的开始,但这并不能将闲散的员工与忙碌的员工分开。您可以使用共享的互斥状态表,文件还是共享内存?或者也许每个孩子通过一个socketpair()传递其状态 - 与用于文件描述符传递的相同 - 传递给父对象?

那么,如果你因为某些原因超过了K,你将如何安全地杀死一个空闲的工人?信号?通过相同的socketpair()给出的命令?一个新空闲的工人是否可以检查状态表终止本身,如果空闲将超过K?您如何从意外工作者终止(例如SEGV)中恢复过来?等等

Apache的MPM prefork模块在这个问题空间中实现了一个可能的设计。你可能想咨询它的想法。

+0

非常感谢!明天我会用你的建议发布我的代码,你可以,请检查一下吗? – 2013-04-29 19:26:29

+1

不会有雷鸣般的牧群。内核将保证只有一个孩子接受工作,其他人不会知道。无论如何,这不是要走的路,因为它使得追踪孩子和他们的国家太难。让父节点接受并传递描述符更容易,然后域套接字已经到位(a)将繁忙/空闲消息传递给父节点; (b)从父母到闲散孩子的“结束你自己”味精; (c)儿童在等候工作时阻挡的便利场所。 – Duck 2013-04-29 20:13:48

+0

@Duck,只是FYI,较老的Linux内核(〜2.2.9?)很容易受到accept()的雷鸣般的冲击。 – pilcrow 2013-04-29 20:37:34

1

您的代码似乎并没有满足条件数2.您处理池没有预先运行。进程在您接受连接时创建。一种解释是你会做一堆叉子,然后让分叉的进程等待接受。一个会得到它,然后它会做处理。

父进程需要跟踪有多少孩子在那里。你可以在一个等待的线程中做到这一点。这将等待一个孩子死亡。 (请参阅man 2等待各种口味。)当进程数量变得太大时,您可以发送一个信号,让孩子们可以捕捉到以便正确终止。然而,我假设父进程不会分岔更多的孩子,直到他们中的一些人死亡,并且不会超额订阅'K'限制。