windows socket編程select模型使用

來源:互聯網
上載者:User

標籤:


int select(

        int nfds,            //忽略        fd_ser* readfds,    //指向一個通訊端集合,用來檢測其可讀性        fd_set* writefds,   // 指向一個通訊端結合,用來檢測其可寫性        fd_ser* exceptfds, //指向一個通訊端集合,用來檢測錯誤        const struct timeval * timeout   //指定此函數等待的最長時間,如果為NULL,則最長時間為無限大。); 參數說明:(1)   nfds  windows下未使用,linux下會使用此參數(2)   readfds:   readfds集合中的通訊端發送在以下三種情況中任意一種就會被視為可讀,select函數返回後繼續留在readfds集合中,不可讀的會被移除readfds集合。1.通訊端有資料可讀,可以對通訊端調用recv函數接收資料2.通訊端的串連已經關閉,重啟或者中斷,此時應該對通訊端進行關閉3.listen被調用,並且有一個串連未決,對 listen通訊端調用accept函數建立新的連結。(3)   writefds:    readfds集合中的通訊端在以下三種情況下會被視為可寫1.使用connect通訊端首次建立連結2.使用accept通訊端被接收3.使用send操作失敗,返回WSAEWOULDBLOCK錯誤,而且緩衝區的空間變得可用send出去的資料其實都先存在winsock的發送緩衝區中,然後才發送出去,如果緩衝區滿了,那麼再調用send(WSASend,sendto,WSASendTo)的話,就會返回一個 WSAEWOULDBLOCK的錯誤碼,接下來隨著發送緩衝區中的資料被發送出去,緩衝區中出現可用空間時,一個 FD_WRITE 事件才會被觸發,這裡比較容易混淆的是 FD_WRITE 觸發的前提是 緩衝區要先被充滿然後隨著資料的發送又出現可用空間,而不是緩衝區中有可用空間(4)   exceptfds   (未使用過,沒有進行深入的研究)1.如果一個非阻塞串連調用正在被處理,串連視圖失敗2.OOB資料可讀(5)   timeout:   設定時間,如果超過設定時間,還沒有網路事件發生,則返回0,如果此參數為NULL,select會無限等待,直到有一個描述字滿足條件。timeout指向一個timeval結構typedef struct timeval{    long tv_sec;       //只是等待多少秒    long tv_usec;     //指示等待多少毫秒} timeval;如果timeval為{0,0},則select()立即返回,這可用於探詢所選套介面的狀態。如果處於這種狀態,則select()調用可認為是非阻塞的,且一切適用於非阻塞調用的假設都適用於它 具體編程流程1.初始化通訊端集合fdSocket,向這個集合添加監聽通訊端2.將fdSocket集合拷貝到fdRead傳遞給select函數,當有時間發送時,select函數移除fdRead集合中沒有未決io操作的通訊端3.比較原來fdSocket集合與select處理後的fdRead集合。確定哪些通訊端有未決IO4.回到第2步繼續處理
my_socket();my_bind(port);my_listen();//PostMessage(h_hand,WM_USER_THREADEND,0,0);//select模型處理過程//(1).初始化通訊端集合fdSocket.添加監聽通訊端控制代碼到這個集合FD_ZERO(&fdSocket);FD_SET(sSock,&fdSocket);while (1){//(2.)將fdSocket集合的一個拷貝fdRead傳遞給select函數//當有時間發生時,select函數一處fdRead集合中沒有未決IO操作的通訊端控制代碼,然後返回。fd_set fdRead = fdSocket;int nRet = select(0,&fdRead,NULL,NULL,NULL);    //timeout參數控制select()完成的時間。若timeout參數為空白指標,則select()將一直阻塞//到有一個描述字滿足條件。否則的話,timeout指向一個timeval結構,其中指定了select()//調用在返回前等待多長時間//fdwrite  1. 接成功的通訊端  在第一次建立串連時,C/S端都會觸發一個FD_WRITE事件//2, 觸發的前提是 緩衝區要先被充滿然後隨著資料的發送又出現可用空間if(nRet>0){//(3)通過原來的fdSocket集合與select處理後的fdRead集合比較//確定哪些通訊端有未決io,並進一步處理這些iofor(int i=0;i<(int)fdSocket.fd_count;i++){if(FD_ISSET(fdSocket.fd_array[i],&fdRead)){if(fdSocket.fd_array[i] == sSock)   //(1)監聽通訊端收到新串連,有新的連結{if(fdSocket.fd_count<FD_SETSIZE)   //判斷集合滿了嗎?{int socke_len = sizeof(remoteAddr);//4.acceptSOCKET cSock = accept(sSock,(SOCKADDR*)&remoteAddr,&socke_len);if(cSock == INVALID_SOCKET){AfxMessageBox("accept failed!\n");printf("accept failed!\n");continue;}FD_SET(cSock,&fdSocket);//printf("接收到一個串連請求!:%s\r\n",inet_ntoa(remoteAddr.sin_addr) );//printf("當前串連到伺服器的用戶端有 %d 個\n",fdSocket.fd_count+1);socket_id = cSock*(-1);PostMessage(h_hand,WM_USER_THREADEND,0,0);}else{AfxMessageBox("too much connections !\n");printf("too much connections \n");continue;}}else{int nRecv = recv(fdSocket.fd_array[i],readText,sizeof(readText),0);socket_id = fdSocket.fd_array[i];if(nRecv>0)    //(2)可讀{readText[nRecv] = ‘\0‘;//HWND   g_WindowHandle=((CDialog *)AfxGetMainWnd())->GetSafeHwnd();PostMessage(h_hand,WM_USER_THREADEND,0,0);}else           //(3)串連關閉,重啟或中斷{closesocket(fdSocket.fd_array[i]);FD_CLR(fdSocket.fd_array[i],&fdSocket);someone_out = TRUE;PostMessage(h_hand,WM_USER_THREADEND,0,0);}}}}}else{AfxMessageBox("failed select()]n");printf("failed select()]n");break;}}

 

以上只是我在項目中使用的部分代碼,最開始的my_socket,my_bind,my_listen都是自己對socket,bind,listen自己重新做的封裝

 

 

windows socket編程select模型使用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.