併發服務器需要使用fork進行實現,其是unix中派生新進程的唯一方法。
fork函數定義
#include <unistd.h>
pid_t fork(void);
調用fork一次,返回兩次:
- 在調用進程(父進程)中返回一次,返回值爲子進程ID;(父進程有多個子進程,通過返回來獲取跟蹤。)
- 在子進程中又返回一次,返回值爲0;(子進程可以通過getppid獲取父進程的ID)
通過返回值告知進程本身當前是子進程還是父進程。
併發服務器:
併發服務器使用fork子進程來服務每個客戶。
典型使用:
listenfd = socket(...);
bind(listenfd , ...);
listen(listenfd , MaxClient);
for(;;)
{
connfd = accept(listenfd, ...);//偵聽套接字轉化爲連接套接字,父進程繼續等待。
if ( pid = fork() == 0)//子進程,父子共享的引用計數值變爲2
{
close(listenfd);//子進程關閉偵聽套接字
do(connfd); //處理子進程連接套接字
close(connfd); //子進程關閉連接套接字 (僅僅把引用計數減1,並不是真的關閉套接字)
exit(0);
}
close(connfd);//父進程關閉連接套接字(引用計數再次減1,若爲0,則真正關閉套接字。)
}
注意,上述代碼中,fork使得父子共享的引用計數變爲2,執行close只是將引用計數減1,套接字真正的清理和資源釋放要等到引用計數爲0時才執行。
如果確實想在某個TCP連接上發生FIN,可以調用shutdown,其不管引用計數就能激發TCP正常終止系列。
#include <unistd.h>
int clode(int sockfd);
#include <sys/socket.h>
int showdown(int sockfd, int howto);
howto的方式有三種分別是
SHUT_RD(0):關閉sockfd上的讀功能,此選項將不允許sockfd進行讀操作。
SHUT_WR(1):關閉sockfd的寫功能,此選項將不允許sockfd進行寫操作。
SHUT_RDWR(2):關閉sockfd的讀寫功能。
併發服務器圖示: