2013-04-28 29 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'限制。