所謂並發伺服器就是在同一個時刻可以處理來自多個用戶端的請求;迴圈伺服器是指伺服器在同一時刻只可以響應一個用戶端的請求。而且對於TCP和UDP通訊端,這兩種伺服器的實現方式也有不同的特點。
1、TCP迴圈伺服器:
首先TCP伺服器接受一個用戶端的串連請求,處理串連請求,在完成這個用戶端的所有請求後中斷連線,然後再接受下一個用戶端的請求。建立TCP迴圈伺服器的演算法如下:
複製代碼代碼如下:
socket(……); //建立一個TCP通訊端
bind(……); //邦定公認的連接埠號碼
listen(……); //傾聽用戶端串連
while(1) //開始迴圈接收用戶端串連
{
accept(……);//接收當前用戶端的串連
while(1)
{ //處理當前用戶端的請求
read(……);
process(……);
write(……);
}
close(……); //關閉當前用戶端的串連,準備接收下一個用戶端串連
}
TCP迴圈伺服器一次只處理一個用戶端的請求,如果有一個用戶端佔用伺服器不放時,其它的客戶機串連請求都得不到及時的響應。因此,TCP伺服器一般很少用迴圈伺服器模型的。
2、TCP並發伺服器:
並發伺服器的思想是每一個用戶端的請求並不由伺服器的主進程直接處理,而是伺服器主進程建立一個子進程來處理。建立TCP並發伺服器的演算法如下:
複製代碼代碼如下:
socket(……); //建立一個TCP通訊端
bind(……); //邦定公認的連接埠號碼
listen(……);//傾聽用戶端串連
while(1) //開始迴圈接收用戶端的接收
{
accept(……);//接收一個用戶端的串連
if(fork(……)==0) //建立子進程
{
while(1)
{ //子進程處理某個用戶端的串連
read(……);
process(……);
write(……);
}
close(……); //關閉子進程處理的用戶端串連
exit(……) ;//終止該子進程
}
close(……); //父進程關閉串連通訊端描述符,準備接收下一個用戶端串連
}
TCP並發伺服器可以解決TCP迴圈伺服器用戶端獨佔伺服器的情況。但同時也帶來了一個不小的問題,即響應客戶機的請求,伺服器要建立子進程來處理,而建立子進程是一種非常消耗資源的操作。
3、UDP迴圈伺服器:
UDP伺服器每次從通訊端上讀取一個用戶端的資料報請求,處理接收到的UDP資料報,然後將結果返回給客戶機。建立UDP迴圈伺服器的演算法如下:
1 socket(……); //建立一個資料報類型的通訊端 2 bind(……); //邦定公認的短口號 3 while(1) //開始接收用戶端的串連 4 { //接收和處理用戶端的UDP資料報 5 recvfrom(……); 6 process(……); 7 sendto(……);//準備接收下一個客戶機的資料報 8 }
消除行號
因為UDP是非連線導向的,沒有一個用戶端可以獨佔伺服器。只要處理過程不是死迴圈,伺服器對於每一個客戶機的請求總是能夠處理的。
UDP迴圈伺服器在資料報流量過大時由於處理任務繁重可能造成客戶技資料報丟失,但是因為UDP協議本身不保證資料報可靠到達,所以UDP協議是允許遺失資料報的。
鑒於以上兩點,一般的UDP伺服器採用迴圈方式4、UDP並發伺服器把並發的概念應用UDP就得到了並發UDP伺服器,和並發TCP伺服器模型一樣是建立子進程來處理的。
建立UDP並發伺服器的演算法如下:
複製代碼代碼如下:
socket(……); //建立一個資料報類型的通訊端
bind(……); //邦定公認的短口號
while(1) //開始接收用戶端的串連
{ //接收和處理用戶端的UDP資料報
recvfrom(……);
if(fork(……)==0) //建立子進程
{
rocess(……);
sendto(……);
}
}
除非伺服器在處理用戶端的請求所用的時間比較長以外,人們實際上很少用這種UDP並發伺服器模型的。
4、多工I/O並發伺服器:
建立子進程會帶來系統資源的大量消耗,為瞭解決這個問題,採用多工I/O模型的並發伺服器。採用select函數建立多工I/O模型的並發伺服器的演算法如下:
初始化(socket,bind,listen);
複製代碼代碼如下:
while(1)
{
設定監聽讀寫檔案描述符(FD_*);
調用select;
如果是傾聽通訊端就緒,說明一個新的串連請求建立
{
建立串連(accept);
加入到監聽檔案描述符中去;
}
否則說明是一個已經串連過的描述符
{
進行操作(read或者write);
}
多工I/O可以解決資源限制問題,此模型實際上是將UDP迴圈模型用在了TCP上面。這也會帶了一些問題,如由於伺服器依次處理客戶的請求,所以可能導致友的客戶會等待很久。