[Windows]7種網路編程I/O模型代碼實現執行個體__編程

來源:互聯網
上載者:User

From: http://blog.csdn.net/woshinia/article/details/8585930

 

部分代碼參考《[WINDOWS網路與通訊程式設計].王豔平》,網路中一些I/O模型的代碼都沒有對socket是否可寫做過深入研究,我這邊會提供一些解決方案。

阻塞模式下,send會發生阻塞(非阻塞模式下send返回WSAEWOULDBLOCK錯誤,重疊I/O下表現為投遞的發送請求一直無法完成)的情況一般可以分為3種 : 

1,  伺服器雖然發送了大量資料,但用戶端並未調用recv函數去接。

2,網路狀況不佳,發送緩衝區中的資料一直發不出去。

3,發送資料量很大,如下載功能,協議發送資料的速度比不上send函數將資料拷貝到發送緩衝區的速度。

對於1,2情況,我們似乎可以直接關閉通訊端,讓用戶端重新請求。但對於3,卻不行。而且實際操作過程中,我們無法區分是1,2,還是3,我們能做的是盡量去保證發送的正確性。當然防止1情況或者2情況中長時間網路不暢,可以設定逾時。若socket一直處於不可寫狀態超過1分鐘,那麼就關閉通訊端。在最後的IOCP模型中就加入了這種逾時機制。其他模型若要加入,可參考它來做。


一,基本的阻塞模型

[cpp] view plain copy print ? #include <WinSock2.h>    #include <Windows.h>    #include <stdio.h>       #pragma comment(lib,"Ws2_32.lib")       DWORD WINAPI WorkThread(void* param)   {       SOCKET* psClient = (SOCKET*)param;       char buf[4096];       while(true)       {           int len = recv(*psClient,buf,4096,0);           if(len <= 0)           {               printf("recv失敗。%d\n",WSAGetLastError());               Sleep(5000);               break;           }           buf[len] = '\0';           printf("收到資料:%s\n",buf);       }       closesocket(*psClient);       delete psClient;       return 0;   }      int main()   {       WSAData wsaData;       if(0 != WSAStartup(MAKEWORD(2,2),&wsaData))       {           printf("WSAStartup失敗。\n",WSAGetLastError());           Sleep(5000);           return 0;       }       USHORT nPort = 3456;       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(SOCKET_ERROR == ::bind(sListen,(sockaddr*)&sin,sizeof(sin)))       {           printf("bind失敗。%d\n",WSAGetLastError());           Sleep(5000);           return -1;       }          ::listen(sListen,5);          while(true)       {           sockaddr_in addrRemote;           int nAddrLen = sizeof(addrRemote);           SOCKET *psClient = new SOCKET;           *psClient = accept(sListen,(sockaddr*)&addrRemote,&nAddrLen);           HANDLE hThread = CreateThread(NULL,0,WorkThread,psClient,0,NULL);           CloseHandle(hThread);       }       closesocket(sListen);       WSACleanup();   }  

#include <WinSock2.h>#include <Windows.h>#include <stdio.h>#pragma comment(lib,"Ws2_32.lib")DWORD WINAPI WorkThread(void* param){SOCKET* psClient = (SOCKET*)param;char buf[4096];while(true){int len = recv(*psClient,buf,4096,0);if(len <= 0){printf("recv失敗。%d\n",WSAGetLastError());Sleep(5000);break;}buf[len] = '\0';printf("收到資料:%s\n",buf);}closesocket(*psClient);delete psClient;return 0;}int main(){WSAData wsaData;if(0 != WSAStartup(MAKEWORD(2,2),&wsaData)){printf("WSAStartup失敗。\n",WSAGetLastError());Sleep(5000);return 0;}USHORT nPort = 3456;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(SOCKET_ERROR == ::bind(sListen,(sockaddr*)&sin,sizeof(sin))){printf("bind失敗。%d\n",WSAGetLastError());Sleep(5000);return -1;}::listen(sListen,5);while(true){sockaddr_in addrRemote;int nAddrLen = sizeof(addrRemote);SOCKET *psClient = new SOCKET;*psClient = accept(sListen,(sockaddr*)&addrRemote,&nAddrLen);HANDLE hThread = CreateThread(NULL,0,WorkThread,psClient,0,NULL);CloseHandle(hThread);}closesocket(sListen);WSACleanup();}

二,無任何最佳化的非阻塞模型

[cpp] view plain copy print ? #include <WinSock2.h>    #include <Windows.h>    #include <stdio.h>    #include <vector>    using namespace std;      #pragma comment(lib,"Ws2_32.lib")       CRITICAL_SECTION g_cs;   HANDLE           g_StartEvent;   vector<SOCKET> g_vecClients;   int g_iVecSize = 0;   DWORD WINAPI WorkThread(void* param)   {       char buf[4096];       while(1)       {           if(g_vecClients.empty())           {               ResetEvent(g_StartEvent);               WaitForSingleObject(g_StartEvent,INFINITE);           }              EnterCriticalSection(&g_cs);           for(vector<SOCKET>::iterator it = g_vecClients.begin();it != g_vecClients.end();)           {               int len = recv(*it,buf,4096,0);               if(len == SOCKET_ERROR)               {                   if(WSAEWOULDBLOCK != WSAGetLastError())                   {                       printf("recv Error:%d\n",WSAGetLastError());                       closesocket(*it);                       it = g_vecClients.erase(it);                   }                   else                   {                       printf("%d.",*it);                       ++it;                   }               }               else               {                   buf[len] = 0;                   printf("收到資料: %s\n",buf);                   ++it;               }           }           LeaveCriticalSection(&g_cs);           Sleep(100);          }       return 0;   }      int main()   {       InitializeCriticalSectionAndSpinCount(&g_cs,4000);       g_StartEvent = CreateEvent(NULL,FALSE,FALSE,NULL);          WSAData wsaDate;       WSAStartup(MAKEWORD(2,2),&wsaDate);       USHORT nport = 3456;       u_long ul = 1;       SOCKET s = socket(AF_INET,SOCK_STREAM,0);       ioctlsocket(s,FIONBIO,&ul);       sockaddr_in sin;       sin.sin_family = AF_INET;       sin.sin_port = htons(nport);       sin.sin_addr.S_un.S_addr = ADDR_ANY;          if(SOCKET_ERROR == ::bind(s,(sockaddr*)&sin,sizeof(sin)))       {           return -1;       }          ::listen(s,5);          HANDLE hThread = CreateThread(NULL,0,WorkThread,NULL,0,NULL);       CloseHandle(hThread);          while(true)       {           sockaddr_in addrRemote;           int nAddrLen = sizeof(addrRemote);           SOCKET sClient = accept(s,(sockaddr*)&addrRemote,&nAddrLen);           if(sClient != SOCKET_ERROR)           {               EnterCriticalSection(&g_cs);               g_vecClients.push_back(sClient);               LeaveCriticalSection(&g_cs);               if(g_vecClients.size() == 1)                   SetEvent(g_StartEvent);           }           else if(WSAEWOULDBLOCK == WSAGetLastError())           {               printf(".");               Sleep(100);           }           else           {               printf("accept failed! %d\n",WSAGetLastError());           }       }       closesocket(s);       WSACleanup();       CloseHandle(g_StartEvent);       DeleteCriticalSection(&g_cs);   }  

#include <WinSock2.h>#include <Windows.h>#include <stdio.h>#include <vector>using namespace std;#pragma comment(lib,"Ws2_32.lib")CRITICAL_SECTION g_cs;HANDLE           g_StartEvent;vector<SOCKET> g_vecClients;int g_iVecSize = 0;DWORD WINAPI WorkThread(void* param){char buf[4096];while(1){if(g_vecClients.empty()){ResetEvent(g_StartEvent);WaitForSingleObject(g_StartEvent,INFINITE);}EnterCriticalSection(&g_cs);for(vector<SOCKET>::iterator it = g_vecClients.begin();it != g_vecClients.end();){int len = recv(*it,buf,4096,0);if(len == SOCKET_ERROR){if(WSAEWOULDBLOCK != WSAGetLastError()){printf("recv Error:%d\n",WSAGetLastError());closesocket(*it);it = g_vecClients.erase(it);}else{printf("%d.",*it);++it;}}else{buf[len] = 0;printf("收到資料: %s\n",buf);++it;}}LeaveCriticalSection(&g_cs);Sleep(100);}return 0;}int main(){InitializeCriticalSectionAndSpinCount(&g_cs,4000);g_StartEvent = CreateEvent(NULL,FALSE,FALSE,NULL);WSAData wsaDate;WSAStartup(MAKEWORD(2,2),&wsaDate);USHORT nport = 3456;u_long ul = 1;SOCKET s = socket(AF_INET,SOCK_STREAM,0);ioctlsocket(s,FIONBIO,&ul);sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(nport);sin.sin_addr.S_un.S_addr = ADDR_ANY;if(SOCKET_ERROR == ::bind(s,(sockaddr*)&sin,sizeof(sin))){return -1;}::listen(s,5);HANDLE hThread = CreateThread(NULL,0,WorkThread,NULL,0,NULL);CloseHandle(hThread);while(true){sockaddr_in addrRemote;int nAddrLen = sizeof(addrRemote);SOCKET sClient = accept(s,(sockaddr*)&addrRemote,&nAddrLen);if(sClient != SOCKET_ERROR){EnterCriticalSection(&g_cs);g_vecClients.push_back(sClient);LeaveCriticalSection(&g_cs);if(g_vecClients.size() == 1)SetEvent(g_StartEvent);}else if(WSAEWOULDBLOCK == WSAGetLastError()){printf(".");Sleep(100);}else{printf("accept failed! %d\n",WSAGetLastError());}}closesocket(s);WSACleanup();CloseHandle(g_StartEvent);DeleteCriticalSection(&g_cs);}

三,select模型


[cpp] view plain copy print ? #include <WinSock2.h>    #include <Windows.h>    #include <MSWSock.h>    #include <stdio.h>    #include <map>    using 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.