select I O復用實現簡單web伺服器

2021-10-07 03:14:14 字數 1965 閱讀 3244

要想實現乙個簡單的web伺服器模型,一般有以下幾種方法:

1. 多程序(主程序監聽,有新的連線就fork乙個子程序建立連線)

2. 多執行緒(主線程監聽,有新的連線就新建乙個子執行緒建立連線)

3. 使用系統函式select去監聽,當有檔案描述符就緒對其進行處理

4. 使用系統函式poll去監聽,當有檔案描述符就緒對其進行處理

5. 使用系統函式epoll去監聽,當有檔案描述符就緒對其進行處理

3,4,5都是單執行緒,基本原理就是有乙個執行緒在監聽是否有新的客戶端請求,如果有的話就在此客戶端和伺服器之間建立乙個連線。如果客戶端傳來有效資料之後該連線的檔案描述符就處於就緒狀態(在linux系統裡一切都是以檔案的形式存在,所以可以直接通過資源的檔案描述符去作業系統資源),然後伺服器會按順序對就緒狀態的檔案進行處理。這就是i/o多路復用的本質。

因為對於乙個tcp請求,耗時主要在網路傳輸,屬於i/o密集型,cpu處理單個請求一般很快,所以這裡採用單執行緒處理,沒有程序或者執行緒之間切換的開銷,也避免了阻塞在無效的連線上(如有些客戶端建立了連線但並沒有傳有效資料或請求,這種連線就沒有必要占用過多系統資源去處理),因此在大多數情況下速度會快。

select是多路復用的第乙個系統函式,他預設最多監聽1024個檔案描述符。後面我會再寫部落格介紹poll以及epoll。

下面是乙個server的實現**以及詳細的注釋,client給server傳小寫字母,server轉化為大寫字母並傳回。

/*

使用select構建乙個簡單的server,實現i/o多路復用。select是單執行緒。

*/#include #include #include #include #include #include #include #define maxline 4096

#define serv_port 8000

int main(int argc, char *ar**)

// 將監聽集置0

fd_zero(&allset);

// 將listenfd放入監聽集

fd_set(listenfd, &allset);

printf("wait connecting...\n");

for (; ;)

// 新的連線

if (fd_isset(listenfd, &rset))

}if (i == fd_setsize)

// 將connfd放入監聽集合

fd_set(connfd, &allset);

// 更新最大檔案描述符

if (connfd > maxfd) maxfd = connfd;

// 更新最大存放有效資料下標

if (i > maxi) maxi = i;

// 如果只建立了乙個新的連線,並沒有被監聽的其他檔案描述符處於就緒狀態,意味著沒有資料需要處理,那麼繼續回到之前select阻塞狀態,等待就緒再進行處理

if (--nready == 0) continue;

}for (i = 0; i <= maxi; i++)

// 業務邏輯,從緩衝區讀入並且轉成大寫,寫入檔案描述符

else

write(sockfd, buf, n);

}if (--nready == 0) break;}}

}close(listenfd);

return 0;

}

將上面**命名為server.c,使用

gcc -o server.o server.c

./server.o

就啟動了伺服器。

這裡我沒有放client端**,不過可以使用系統命令:

nc localhost 8000

去模擬乙個客戶端請求(我伺服器端口設定的8000,可以進行更改)。這樣客戶端伺服器就可以進行通訊了。

select IO復用機制

注 select 原理圖,摘自ibm iseries 資訊中心。返回值返回對應位仍然為1的fd的總數。引數 1.2.1 清空描述符集合fd zero fd set 1.2.2 向描述符集合新增指定描述符fd set int,fd set 1.2.3 從描述符集合刪除指定描述符fd clr int,f...

select io 多路復用

select主要用於檢測多個fd狀態,可檢測fd大小收核心編譯巨集 fd setsize限制,預設為1024。當開啟的fd較多時,select的效率會降低。可修改下面簡單伺服器模型為僅接受連線,當fd數量超過20000時,select返回明顯變慢。void testselectsocket else...

select I O多路復用

使用select函式的套接字 如果你想保持現有連線的同時,偵聽新的連線,怎麼辦呢?普通的做法 使用recv,accept是做不到的 當使用accetp等待新的連線時,程式是阻塞的,也就沒辦法再同原有連線保持通訊。另一種做法是,使用非阻塞方式,但這會浪費了寶貴的cpu時間 你的不停的輪詢輪詢 有沒有更...