套接字I O模型之WSAEventSelect

2021-05-11 14:11:01 字數 3949 閱讀 8322

套接字模式和套接字i/o模型的區別。

套接字模式:阻塞套接字和非阻塞套接字。或者叫同步套接字和非同步套接字。

套接字模型:描述如何對套接字的i/o行為進行管理。

winsock提供的i/o模型一共有五種:

1:select模型(選擇模型)

先看一下下面的這句**:

intiresult=recv(s,buffer,1024);

這是用來接收資料的,在預設的阻塞模式下的套接字裡,recv會阻塞在那裡,直到套接字連線上有資料可讀,把資料讀到buffer裡後recv函式才會返回,不然就會一直阻塞在那裡。在單執行緒的程式裡出現這種情況會導致主線程(單執行緒程式裡只有乙個預設的主線程)被阻塞,這樣整個程式被鎖死在這裡,如果永遠沒資料傳送過來,那麼程式就會被永遠鎖死。這個問題可以用多執行緒解決,但是在有多個套接字連線的情況下,這不是乙個好的選擇,擴充套件性很差。select模型就是為了解決這個問題而出現的。

再看**:

intiresult=ioctlsocket(s,fiobio,(unsignedlong*)&ul);

iresult=recv(s,buffer,1024);

這一次recv的呼叫不管套接字連線上有沒有資料可以接收都會馬上返回。原因就在於我們用ioctlsocket把套接字設定為非阻塞模式了。不過你跟蹤一下就會發現,在沒有資料的情況下,recv確實是馬上返回了,但是也返回了乙個錯誤:wsaewouldblock,意思就是請求的操作沒有成功完成。看到這裡很多人可能會說,那麼就重複呼叫recv並檢查返回值,直到成功為止,但是這樣做效率很成問題,開銷太大。

感謝天才的微軟工程師吧,他們給我們提供了好的解決辦法。

先看看select函式

intselect(

intnfds,

fd_setfar*readfds,

fd_setfar*writefds,

fd_setfar*exceptfds,

conststructtimevalfar*timeout

第乙個引數不要管,會被系統忽略的。第二個引數是用來檢查套接字可讀性,也就說檢查套接字上是否有資料可讀,同樣,第三個引數用來檢查資料是否可以發出。最後乙個是檢查是否有帶外資料可讀取。

引數詳細的意思請去看msdn,這裡限於篇幅不詳細解釋了。

最後乙個引數是用來設定select等待多久的,是個結構:

structtimeval  

::listen(slisten, 5);  

// 建立事件物件,並關聯到新的套節字  

wsaevent event = ::wsacreateevent();  

::wsaeventselect(slisten, event, fd_accept|fd_close);  

// 新增到表中  

eventarray[neventtotal] = event;  

sockarray[neventtotal] = slisten;     

neventtotal++;  

// 處理網路事件  

while(true)  

socket snew = ::accept(sockarray[i], null, null);   //tcp握手

wsaevent event = ::wsacreateevent();  

::wsaeventselect(snew, event, fd_read|fd_close|fd_write);  

// 新增到表中  

eventarray[neventtotal] = event;  

sockarray[neventtotal] = snew;    

neventtotal++;  

}  

}  

else if(event.lnetworkevents & fd_read)         // 處理fd_read通知訊息  

}  

}  

else if(event.lnetworkevents & fd_close)        // 處理fd_close通知訊息  

::listen(slisten, 5);

// 建立事件物件,並關聯到新的套節字

wsaevent event = ::wsacreateevent();

::wsaeventselect(slisten, event, fd_accept|fd_close);

// 新增到表中

eventarray[neventtotal] = event;

sockarray[neventtotal] = slisten; 

neventtotal++;

// 處理網路事件

while(true)

socket snew = ::accept(sockarray[i], null, null);

wsaevent event = ::wsacreateevent();

::wsaeventselect(snew, event, fd_read|fd_close|fd_write);

// 新增到表中

eventarray[neventtotal] = event;

sockarray[neventtotal] = snew; 

neventtotal++;}}

else if(event.lnetworkevents & fd_read)   // 處理fd_read通知訊息}}

else if(event.lnetworkevents & fd_close)  // 處理fd_close通知訊息

// 建立事件物件,並關聯到新的套節字  

wsaevent event = ::wsacreateevent();  

::wsaeventselect(s, event, fd_read|fd_close);  

// 新增到表中  

eventarray[neventtotal] = event;  

sockarray[neventtotal] = s;   

neventtotal++;  

// 處理網路事件  

while(true)  

}  

}  

}  

}  

}  // 事件控制代碼和套節字句柄表

wsaevent eventarray[wsa_maximum_wait_events];

socket  sockarray[wsa_maximum_wait_events];

int neventtotal = 0;

ushort nport = 6000; // 此伺服器監聽的埠號

// 建立監聽套節字

socket s = ::socket(af_inet, sock_dgram, ipproto_udp); 

sockaddr_in sin;

sin.sin_family = af_inet;

sin.sin_port = htons(nport);

sin.sin_addr.s_un.s_addr = inaddr_any;

if(::bind(s, (sockaddr*)&sin, sizeof(sin)) == socket_error)

// 建立事件物件,並關聯到新的套節字

wsaevent event = ::wsacreateevent();

::wsaeventselect(s, event, fd_read|fd_close);

// 新增到表中

eventarray[neventtotal] = event;

sockarray[neventtotal] = s; 

neventtotal++;

// 處理網路事件

while(true)}}

}}} udp例子就是在乙個普通套接字上關聯乙個事件物件以及fd_read網路事件。

套接字i o模型

當套接字建立時,預設情況下是工作在阻塞模式。在阻塞模式下,執行i o的winsock呼叫 如send 和recv 一直到操作完成時才返回。比如呼叫recv 函式,如果對應的緩衝區沒有資料到來。呼叫者將會一直等待下去,直到有資料到達為止。1 阻塞 blocking 模型 對於以下函式呼叫 int ir...

套接字I O模型

在unix下可用的5種i o模型為 柱塞i o模型 非柱塞i o模型 i o復用 select和poll 訊號驅動式i o sigio 非同步i o 柱塞式i o模型 最流行的i o模型是柱塞式i o模型,預設情況下所有套接字都是用柱塞的,以資料報套接字為例子,如圖 程序呼叫recvfrom,其系統...

套接字之重疊I O模型

剛剛把重疊i o套接字理解了一點,於是在此做個筆記,給出乙個重疊i o處理單個套接字的程式。這個程式是tcp的伺服器端程式。該程式只能接收乙個客戶端的連線,迴圈傳送資訊,以及該客戶端退出時伺服器端得到響應。套接字型檔初始化等 省略了,只包含乙個監聽部分和乙個處理i o部分的 如下 開始進行重疊i o...