Linux 網絡編程(IO模型)

針對linux 操做系統的5類IO模型,阻塞式、非阻塞式、多路複用、信號驅動和異步IO進行整理,參考《linux網絡編程》及相關網絡資料。linux

阻塞模式編程

在socket編程(以下圖)中調用以下四類函數致使阻塞:緩存

  • 讀操做(read、readv、recv、recvfrom、recvmsg):當應用程序調用讀函數,該系統調用進入內核態,若套接字接收緩衝區無數據則阻塞,數據到達則將接收緩衝區數據拷貝至進程緩衝區並返回。對TCP而言,一旦接收緩衝區中與數據則進程被喚醒,對UDP而言有完整的UDP報文達到進程被喚醒。
  • 寫操做(write、writev、send、sendto、sendmsg):當發送緩衝區空間小於寫操做要求寫的數量則阻塞,該狀況發生不多。對UDP而言,不存在發送緩衝區,所以不可能發送阻塞。
  • 接收鏈接(accept):TCP協議採用傾聽套接字接收客戶機鏈接請求,完成三次握手的TCP鏈接保存在傾聽套接字完成隊列。當accept被調用時,若完成隊列爲空則阻塞。當有新的TCP鏈接,進程被喚醒同時分配一個新的鏈接套接字標識這個TCP鏈接。
  • 創建鏈接(connect):TCP套接字調用connect與服務器鏈接時進程將阻塞,待3次握手操做完成後(內核態)進程被喚醒。

非阻塞模式服務器

針對上述四類阻塞模式的socket調用,都可經過設置的方式使其非阻塞。設置方式有兩種fcntl設置套接字爲O_NONBLOCK,以及ioctl設置FIONBIO。完成後其四類操做非阻塞,以下:網絡

  • 讀操做:緩衝區無數據,函數以錯誤EWOULDBLOCK返回;
  • 寫操做:發送緩衝區無空間,函數以錯誤EWOULDBLOCK返回;
  • 接收鏈接:若隊列中無新的鏈接,函數以錯誤EWOULDBLOCK返回;
  • 鏈接操做:若鏈接不能立刻創建,返回錯誤類型EINPROGRESS;

非阻塞模式在運用中採用輪詢,或配合select的方式使用。異步

多路複用socket

進程定義讀描述符集、寫描述符集以及異常描述符集(做爲select的入參),在select被調用時若是沒有描述符集就緒,該select將被阻塞。當有任何一個或幾個描述符就緒時,select設置描述符集,並返回就緒描述符的個數。函數

/*
* 多路複用select函數,參數定義以下
* nfds: select監視的文件句柄數,通常設置爲最大文件號+1
* readfds:select監視的可讀文件句柄集合
* writefds:select監視的可寫文件句柄集合
* exceptfds:select監視的異常文件句柄集合
*/
int
select(nfds, readfds, writefds, exceptfds, timeout)

 注:對於監視一個描述符的狀況,select與阻塞模式無區別。spa

信號驅動操作系統

信號驅動的方式屬於一種異步的IO方式,進程自己不會被掛起,流程以下:

 

信號驅動的IO方式主要分如下三步操做:

signal(SIGIO,sig_handler); //設置SIGIO信號對應的處理函數
fcntl(sockfd,F_SETOWN, getpid());//設置接收SIGIO信號的進程爲當前進程,該信號由sockfd句柄產生
ioctl(sockfd,FIOASYNC,&on);//容許sockfd套接字進行信號驅動的輸入輸出

 

 對於UDP套接字,內核在如下狀況下發送信號SIGIO:

  • 套接字上接收到一個UDP數據報
  • 套接字上發生一個異步錯誤

對TCP套接字,內核在如下狀況下發送信號SIGIO:

  • 在傾聽套接字上,一個鏈接請求完成
  • 初始化了一個斷開鏈接的請求
  • 斷開鏈接請求完成
  • 一個方向的鏈接被關閉
  • 數據到達套接字
  • 套接字發送了數據
  • 異步錯誤發生

異步IO

異步IO是linux 2.6內核的標準特性,基本思想是容許進程發起不少IO操做,而不用阻塞或等待任何操做。稍後在接收到IO操做完成的通知時,再檢索IO操做的結果。

aio過程的數據緩存在結構體aiocb中,該結構體定義以下:

struct aiocb
{
  int aio_fildes;               /* File desriptor.  */ int aio_lio_opcode;           /* Operation to be performed.  */int aio_reqprio;              /* Request priority offset.  */ volatile void *aio_buf;       /* Location of buffer.  */ 
  size_t aio_nbytes;            /* Length of transfer.  */struct sigevent aio_sigevent; /* Signal number and value.  */ 

 

根據posix.1b所要求,主要包括以下函數:

  • aio_read(struct aiocb* aiocbp); //進行異步讀操做
  • aio_write(struct aiocb* aiocbp);//進行異步寫操做
  • aio_error(struct aiocb* aiocbp);//肯定請求的狀態
  • aio_return(struct aiodb* aiocbp);//讀寫的異步返回
相關文章
相關標籤/搜索