FD_READ 事件很是容易掌握. 當有數據發送過來時, WinSock 會以 FD_READ 事件通知你, 對於每個 FD_READ 事件, 你須要像下面這樣調用 recv() :
int bytes_recv = recv(wParam, &data, sizeof(data), 0);
基本上就是這樣, 別忘了修改上面的 wParam. 還有, 不必定每一次調用 recv() 都會接收到一個完整的數據包, 由於數據可能不會一次性所有發送過來. 因此在開始處理接收到的數據以前, 最好對接收到的字節數 ( 即 recv() 的返回值) 進行判斷, 看看是否收到的是一個完整的數據包.
FD_WRITE 相對來講就麻煩一些. 首先, 當你創建了一個鏈接時, 會產生一個 FD_WRITE 事件. 可是若是你認爲在收到 FD_WRITE 時調用 send() 就萬事大吉, 那就錯了.
FD_WRITE 事件只在發送緩衝區有多出的空位, 能夠容納須要發送的數據時纔會觸發.
上面所謂的發送緩衝區,是指系統
就是說你得先把發送緩衝區填滿.底層提供的緩衝區. send() 先將數據寫入到發送緩衝區中, 而後經過網絡發送到接收端. 你或許會想, 只要不把發送緩衝區填滿, 讓發送緩衝區保持足夠多的空位容納須要發送的數據, 那麼你就會源源不斷地收到 FD_WRITE 事件了. 嘿嘿, 錯了.上面只是說 FD_WRITE 事件在發送緩衝區有多出的空位時會觸發, 但不是在有足夠的空位時觸發,
一般的辦法是在一個無限循環中不斷的發送數據, 直到把發送緩衝區填滿. 當發送緩衝區被填滿後, send() 將會返回 SOCKET_ERROR , WSAGetLastError() 會返回 WSAWOULDBLOCK . 若是當前這個 SOCKET 處於阻塞(同步)模式, 程序會一直等待直到發送緩衝區空出位置而後發送數據; 若是SOCKET是非阻塞(異步)的,那麼你就會獲得 WSAWOULDBLOCK 錯誤. 因而只要咱們首先循環調用 send() 直到發送緩衝區被填滿, 而後當緩衝區空出位置來的時候, 系統就會發出FD_WRITE事件. 有沒有想過我能指出這一點來是多麼不容易, 你可真走運. 下面是一個處理 FD_WRITE 事件的例子.
case FD_WRITE: // 能夠發送數據了
{
// 進入無限循環
while(TRUE)
{
// 從文件中讀取數據, 保存到 packet.data 裏面.
in.read((char*)&packet.data, MAX_PACKET_SIZE);
// 發送數據
if (send(wparam, (char*)(&packet), sizeof(PACKET), 0) == SOCKET_ERROR)
{
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
// 發送緩衝區已經滿了, 退出循環.
break;
}
else // 其餘錯誤
{
// 顯示出錯信息而後退出.
CleanUp();
return(0);
}
}
}
} break;
看到了吧, 實現其實一點也不困難. 你只是弄混了一些概念而已. 使用這樣的發送方式, 在發送緩衝區變滿的時候就能夠退出循環. 而後, 當緩衝區空出位置來的時候, 系統會觸發另一個 FD_WRITE 事件, 因而你就能夠繼續發送數據了.
在你開始使用新學到的知識以前, 我還想說明一下 FD_WRITE 事件的使用時機.
若是你不是一次性發送大批量的數據的話, 就別想着使用 FD_WRITE 事件了, 緣由很簡單 - 若是你寄指望於在收到 FD_WRITE 事件時發送數據, 可是卻又不能發送足夠的數據填滿發送緩衝區, 那麼你就只能收到鏈接剛剛創建時觸發的那一次 FD_WRITE - 系統不會觸發更多的 FD_WRITE 了. 因此當你只是發送儘量少的數據的時候, 就忘掉 FD_WRITE 機制吧, 在任何你想發送數據的時候直接調用 send() . 結論 這是我寫過的最長的一篇文章. 我也曾試圖儘量把它寫短一些來吸引你的注意力, 可是有太多的內容要包括. 在剛剛使用異步SOCKET 時, 若是你沒有正確地理解它, 真的會把本身搞胡塗. 我但願個人文章教會了你如何使用它們. ___________________________________ 這是我在 GOOGLE 上搜到的一篇文章中的一部分. 雖然原做者的部分觀點彷佛並不正確, 可是文章寫得很易懂. 其實, 若是你想收到 FD_WRITE事件而你又沒法先填滿發送緩衝區, 能夠調用 WSAAsyncSelect( ..., FD_WRITE ). 若是當前發送緩衝區有空位, 系統會立刻給你發 FD_WRITE 事件. FD_WRITE 消息, MFC 的 CAsyncSocket 類將其映射爲 OnSend() 函數. FD_READ 消息, 被映射爲 OnReceive() 函數.