winsock提供了一些i/o模型幫助應用程式以非同步方式在乙個或者多個套接字上管理i/o。大體上,這樣的i/o模型共有6中:阻塞模型,選擇模型,wsaasyncselect模型,wsaeventselect模型,重疊模型和完成埠模型。
本章先介紹套接字模型、選擇模型、wsaasyncselect模型
4.1 套接字模式
套接字模式簡單的決定了操作套接字時,winsock函式是如何運轉的。 winsock以兩種模式執行i/o操作:阻塞和非阻塞。 在阻塞模式下,執行i/o的winsock呼叫(如send和recv)一直到操作完成菜返回。 在非阻塞模式下,winsock函式會立即返回。
4.1.1 阻塞模式
套接字建立時,預設工作在阻塞模式下。 例如,對recv函式的呼叫會使程式進入等待狀態,直到接收到資料才返回。
大多數winsock程式設計者都是從阻塞套接字模式開始學習的,因為這時最容易和最直接的方式。處理阻塞模式套接字的應用程式使用的程式框架便是阻塞模式。 此模型是非常容易理解的。
阻塞套接字的好處是使用簡單,但是當需要處理多個套接字連線時,就必須建立多個執行緒,即典型的乙個連線使用乙個執行緒的問題。這給程式設計帶來了許多不方便。所以實際開發中使用最多的還是下面要講述的非阻塞模式。
4.1.2 非阻塞模式
非阻塞套接字使用起來比較複雜, 但是卻有許多有點。 應用程式可以呼叫ioctlsocket函式顯示地讓套接字工作在非阻塞模式下。
u_long ul = 1;
socket s = socket(af_inet, sock_stream, 0);
ioctlsocket(s, fionbio, (u_long*)&ul);
一旦套接字被置於非阻塞模式, 處理傳送和接收資料或者管理連線的winsock呼叫將會立即返回。 大多情況下,呼叫失敗的出錯**是wsaewouldblock, 這意味著請求的操作在呼叫期間沒有完成。例如,如果系統輸入緩衝區中沒有待處理的資料,那麼對recv的呼叫將返回wsaewouldblock。 通常,要對相同函式呼叫多次,直到它返回成功為止。
非阻塞呼叫經常用wsaewouldblock出錯**失敗,所以將套接字設定為非阻塞之後,關鍵的問題在於如何確定套接字什麼時候可讀/可寫, 也就是說確定網路事件何時發生。如果需要字集不斷呼叫函式去測試的話,程式的效能勢必會受到影響,解決的辦法就是使用windows提供的不同的i/o模型。
4.2 選擇(select)模型
select模型是乙個廣泛在winsock中使用的i/o模型。 稱它為select模型,是因為它主要是使用select函式管理i/o的。 這個模式的設計源於unix系統, 目地是允許那些想要避免在套接字呼叫上阻塞的應用程式有能力管理多個套接字。
4.2.1 select函式
select 函式可以確定乙個或者多個套接字的狀態。 如果套接字上沒有網路事件發生,便進入等待狀態,以便執行同步i/o。 函式定義如下
int select(
int nfds, // 忽略, 僅是為了與berkeley套接字相容
fd_set* readfds, // 指向乙個套接字集合, 用來檢查其可讀性
fd_set* writefds, // 指向乙個套接字集合, 用來檢查其可寫性
fd_set* exceptfds, // 指向乙個套接字集合, 用來檢查錯誤
const struct timeval* timeout // 指定此函式等待的最長事件, 如果是null, 則最長時間為無限大
);
函式呼叫成功,返回發生網路事件的所有套接字數量的總和。 如果超過了時間限制,返回0, 失敗則返回socket_error。
1 套接字集合
fd_set 結構可以把多個套接字連在一起, 形成乙個套接字集合。 select函式可以測試這個集合中哪些套接字有事件發生。 下面是這個結構在winsock2.h中的定義。
typedef struct fd_set
fd_set;
下面是winsock定義的4個操作fd_set套接字集合的巨集
fd_zero(*set) 初始化set為空集合。 集合在使用前應該總是清空。
fd_clr(s,*set) 從set移除套接字s
fd_isset(s, *set) 檢查s是不是set的成員,如果是返回true
fd_set(s, *set) 新增套接字到集合
2 網路事件
傳遞給select函式的3個fd_set結構中, 乙個是為了檢查可讀性, 乙個是為了檢查可行性, 另乙個是為了檢查錯誤。
select函式返回之後, 如果有下列事件發生, 其對應的套接字就會被標識。
(1)readfds集合
資料可讀
連線已經關閉、重啟或者中斷
如果listen已經被呼叫, 並且有乙個連線,accept函式將成功
(2)writefds集合:
資料能夠傳送
如果乙個非阻塞連線呼叫正在被處理,連線已經成功
(3)exceptfds集合:
如果乙個非阻塞連線呼叫正在被處理,連線試圖失敗
oob資料可讀
當select返回時,它通過移除沒有未決i/o操作的套接字控制代碼修改每個fd_set集合。 例如,想要測試套接字s是否可讀時,必須將它新增到readfds集合,然後等待select函式返回。當select呼叫完成後再確定s是否仍然還在readfds集合中, 如果還在,就說明s可讀了。 3個引數中的任意兩個都可以是null(至少要有乙個不是null), 任何不是null的集合必須至少包含乙個套接字控制代碼。
3、設定超時
最後的引數timeout是timeval結構的指標, 它制定了select函式等待的最長事件。 如果設為null, select將會無限則色,直到有網路事件發生,timeval結構定義如下:
typedef struct timeval
timeval;
18 3 3 套接字位址
每個套接字域都有獨特的位址格式。對於乙個 af unix 套接字來說,它的位址是由乙個包含在 sys un.h 標頭檔案裡的 sockaddr un 結構描述的。該結構的定義為 struct sockaddr un 因為不同型別的位址都需要傳遞到對套接字程序處理的系統呼叫裡去,所以定義各種位址格式時...
socket程式設計(一) 套接字
socket程式設計 一 套接字 1.套接字基礎 套接字是一種網路api 應用程式程式設計介面 可以使應用它開發網路程式。套接字介面提供一種程序間通訊的方法,使得在相同或不同的主機上的程序能以相同的規範進行雙向資訊傳送。程序通過呼叫套接字介面來實現相互之間的通訊,而套接字介面又利用下層的網路協議功能...
網路程式設計7 套接字關閉
close 函式 int close int sockfd close函式會對套接字引用計數減一,一旦發現套接字引用計數到0,就會關閉tcp兩個方向的資料流,並徹底釋放套接字 在輸入方向上,系統核心會將套接字設定為不可讀,任何讀操作都會返回異常 在輸出方向上,系統核心嘗試將傳送緩衝區的資料傳送給對端...