1. 程式人生 > >併發伺服器:多路複用I/O

併發伺服器:多路複用I/O

在實際的應用中,要求一個伺服器能同時處理大量的客戶請求,所有這些客戶將訪問綁
定在某一個特定套接字地址上的伺服器。因此,伺服器必須滿足併發的需求。如果不採用並
發技術,當伺服器處理一個客戶請求時,會拒絕其他客戶端請求,造成其他客戶要不斷的請
求並長期等待。
在Linux(Unix)系統中併發伺服器有三種設計方式:
(1)多程序
程序是執行中的計算機程式,可以認為是一個程式的一次執行。它是一個動態的實體,
是獨立的任務。每個單獨的程序執行在自己的虛擬地址空間中,並且它只能通過安全的核心
管理機制和其它程序互動。若是一個程序崩潰不會引起其它程序崩潰。
在Linux(Unix)系統中,多個程序可以同時執行相同的程式碼,從而支援併發。
對於單個CPU 系統而言,CPU 一次只能執行一個程序,但作業系統可通過分時處理,
每個程序在每個時間段中執行,因此對於使用者而言,這些程序在同時執行。
(2)多執行緒
執行緒與程序類似,也支援併發執行。與程序不同的一點,在同一程序中所有執行緒共享
相同的全程變數以及系統分配給程序的資源。因此,執行緒佔用較少的系統資源,並且執行緒之
間切換更快。
(3)I/O 多路複用(select 和poll 函式)
另一種支援併發的方法是I/O 多路複用。select()函式是系統提供的,它可以在多個描
述符中選擇被啟用的描述符進行操作。
例如:一個程序中有多個客戶連線,即存在多個TCP 套接字描述符。select()函式阻塞
直到任何一個描述符被啟用,即有資料傳輸。從而避免了程序為等待一個已連線上的資料而
無法處理其他連線。因而,這是一個時分複用的方法,從使用者角度而言,它實現了一個程序
或執行緒中的併發處理。

I/O 多路複用技術的最大優勢是系統開銷小,系統不必建立程序、執行緒,也不必維護這
些程序/執行緒,從而大大減少了系統的開銷。
select()函式用於實現I/O 多路複用,它允許程序指示系統核心等待多個事件中的任何一
個發生,並僅在一個或多個事情傳送或經過某指定的時間後才喚醒程序。
它的原型如下,
#include<sys/time.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set * errorfds, struct timeval *timeout);
ndfs: select() 函式監視描述符數的最大值。根據程序中開啟的描述符數而定,一般設為要
監視的描述符的最大數加1。
readfds: select() 函式監視的可讀描述符集合。
writefds: select()函式監視的可寫描述符集合。
errorfds: select()函式監視的異常描述符集合。
timeout: select()函式超時結束時間
返回值。如果成功返回總的位數,這些位對應已準備好的描述符。否則返回-1,並在errno
中設定相應的錯誤碼。
FD_ZERO(fd_set *fdset):清空fdset 與所有描述符的聯絡
FD_SET(int fd, fd_set *fdset):建立描述符fd 與fdset 的聯絡
FD_CLR(int fd, fd_set *fdset):撤銷描述符fd 與fdset 的聯絡
FD_ISSET(int fd,fd_set *fdset) ::檢查與fdset 聯絡的描述符fd 是否可讀寫,返回非0表示可讀寫。
採用select()函式實現I/O 多路複用的基本步驟如下:
(1) 清空描述符集合
(2) 建立需要監視的描述符與描述符集合的聯絡
(3) 呼叫select()函式
(4) 檢查所有需要監視的描述符,利用FD_ISSET 判斷是否準備好
(5) 對已準備好的描述符進行I/O 操作