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