套接字模式和套接字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...