生活随笔
收集整理的這篇文章主要介紹了
Windsock套接字I/O模型学习 --- 第二章
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1. select模型
select模型主要借助于apiselect來實現,所以先介紹一下select函數
int select(
int nfds, // 忽略,僅是為了與 Berkeley 套接字兼容
fd_set* readfds, // 指向一個套接字集合,用來檢查其可讀性
fd_set* writefds, // 指向一個套接字集合,用來檢查其可寫性
fd_set* exceptfds, // 指向一個套接字集合,用來檢查錯誤
const struct timeval* timeout // 指定此函數等待的最長時間,如果為 NULL,則最長時間為無限大
);// fd_set結構體
typedef struct fd_set {
u_int fd_count; // 下面數組的大小
SOCKET fd_array[FD_SETSIZE]; // 套接字句柄數組
} fd_set;FD_ZERO(*set) //初始化 set 為空集合。集合在使用前應該總是清空
FD_CLR(s, *set) //從 set 移除套接字 s
FD_ISSET(s, *set) //檢查 s 是不是 set 的成員,如果是返回 TRUE
FD_SET(s, *set) //添加套接字到集合
2.例子
一個簡單的流程:
初始化套接字集合 fdSocket,向這個集合添加監聽套接字句柄。將 fdSocket 集合的拷貝 fdRead 傳遞給 select 函數,當有事件發生時, select 函數移除 fdRead 集合中沒有未決 I/O 操作的套接字句柄,然后返回。比較原來 fdSocket 集合與 select 處理過的 fdRead 集合,確定哪些套接字有未決 I/O,并進一步處理這些 I/O。回到第 2 步繼續進行選擇處理。 CInitSock theSock; // 初始化 Winsock 庫
int main()
{USHORT nPort = 4567; // 此服務器監聽的端口號// 創建監聽套接字SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(nPort);sin.sin_addr.S_un.S_addr = INADDR_ANY;// 綁定套接字到本地機器if (::bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR){printf(" Failed bind() \n");return -1;}// 進入監聽模式::listen(sListen, 5);// select 模型處理過程// 1)初始化一個套接字集合 fdSocket,添加監聽套接字句柄到這個集合fd_set fdSocket; // 所有可用套接字集合FD_ZERO(&fdSocket);FD_SET(sListen, &fdSocket);while (TRUE){ // 2)將 fdSocket 集合的一個拷貝 fdRead 傳遞給 select 函數,// 當有事件發生時, select 函數移除 fdRead 集合中沒有未決 I/O 操作的套接字句柄,然后返回。fd_set fdRead = fdSocket;int nRet = ::select(0, &fdRead, NULL, NULL, NULL);if (nRet > 0){ // 3)通過將原來 fdSocket 集合與 select 處理過的 fdRead 集合比較,// 確定都有哪些套接字有未決 I/O,并進一步處理這些 I/O。for (int i = 0; i < (int)fdSocket.fd_count; i++){if (FD_ISSET(fdSocket.fd_array[i], &fdRead)){if (fdSocket.fd_array[i] == sListen) // ( 1)監聽套接字接收到新連接{if (fdSocket.fd_count < FD_SETSIZE){sockaddr_in addrRemote;int nAddrLen = sizeof(addrRemote);SOCKET sNew =::accept(sListen, (SOCKADDR*)&addrRemote, &nAddrLen);FD_SET(sNew, &fdSocket);printf("接收到連接( %s) \n", ::inet_ntoa(addrRemote.sin_addr));}else{printf(" Too much connections! \n");continue;}}else{char szText[256];int nRecv = ::recv(fdSocket.fd_array[i], szText, strlen(szText), 0);if (nRecv > 0) // ( 2)可讀{szText[nRecv] = '\0';printf("接收到數據: %s \n", szText);}else // ( 3)連接關閉、重啟或者中斷{::closesocket(fdSocket.fd_array[i]);FD_CLR(fdSocket.fd_array[i], &fdSocket);}}}}}else{printf(" Failed select() \n");break;}}return 0;
}
3.好處
使用 select 的好處是程序能夠在單個線程內同時處理多個套接字連接,這避免了阻塞模
式下的線程膨脹問題。但是,添加到 fd_set 結構的套接字數量是有限制的,默認情況下,最
大值是 FD_SETSIZE,它在 winsock2.h 文件中定義為 64。為了增加套接字數量,應用程序可
以將 FD_SETSIZE 定義為更大的值(這個定義必須在包含 winsock2.h 之前出現)。不過,自
定義的值也不能超過 Winsock 下層提供者的限制(通常是 1024)
轉載于:https://www.cnblogs.com/zjzyh/p/5459581.html
總結
以上是生活随笔為你收集整理的Windsock套接字I/O模型学习 --- 第二章的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。