UDP使用IOCP

UDP使用IOCP

  (2010-12-31 11:27:45)
标签: 

端口

 

system_info

 

相关信息

 

线程

 

分配


在WSARecvFrom成功以后,IOCP得到了投递,处理完了这个数据,这个时候应该重新发起一个WSARecvFrom投递了,这个时候要特别注意,
不要重新分配一个Overlapped,而要复用当前这个,不然在GetQueued的时候,会报错,报0xC000000005,读取0×00000010错误。

网上的IOCP都是TCP的,UDP的资料太少,这里提出一个要注意的地方,以使后来人避免走弯路
查看源代码
打印帮助
01    class CIOCPServer
02    {
03          CString m_sConnectString;
04    
05    public:
06          CDatabase m_Database;
07         
08          CIOCPServer();
09          virtual ~CIOCPServer();
10    
11          //2005.6.2
12          BOOL StartServer();
13          BOOL StopServer();
14    
15          BOOL InitSocket(SOCKET_STYPE stype,int port, int num = -1);
16    
17          //绑定在端口上工作线程
18          static DWORD WINAPI CompletionWorkerThread( void * lpParam);
19    
20    private:
21          BOOL ProcessLoadMsg(LPCLIENTCONTEXT lpContext);
22    
23    private:
24          //根据消息overlapped的类型,处理消息
25          BOOL ProcessIOMessage(SOCKET_STYPE stype,IOType opCode, LPCLIENTCONTEXT lpContext , DWORD dwIoSize);
26    
27          //在端口上产生线程,并创建完成端口
28          void CreateWorkerThread();
29          //关闭完成端口
30          void CloseCompletionPort();
31          //分配连接overlappedplus
32          LPOVERLAPPEDPLUS AllocateOverlappedPlus(IOType ioType);
33          //分配连接进入的客户的相关信息
34          LPCLIENTCONTEXT AllocateContext();
35          //释放overlappedplus
36          void FreeOverlappedPlus(LPOVERLAPPEDPLUS lpOlp);
37    private:
38    
39          HANDLE m_hIocp; //完成端口句柄
40          DWORD m_dwThreads; //线程数
41    };

CPP方式:
查看源代码
打印帮助
001    #include "IOCPServer.h"
002    
003    #include "common.h"
004    
005    CIOCPServer::CIOCPServer()
006    {
007           //socket初始化
008          WSADATA wsd;
009          WORD wVersionRequested = MAKEWORD(2, 2);
010          int nResult = WSAStartup(wVersionRequested, &wsd);
011          if (nResult == SOCKET_ERROR)
012          {
013               WSACleanup();
014          }
015    
016          if (LOBYTE(wsd.wVersion) != 2 || HIBYTE(wsd.wVersion) != 2)
017          {
018               WSACleanup();
019          }
020    
021    }
022    
023    CIOCPServer::~CIOCPServer()
024    {
025          WSACleanup();
026    }
027    
028    //分配连接overlappedplus
029    LPOVERLAPPEDPLUS CIOCPServer::AllocateOverlappedPlus(IOType ioType)
030    {
031          OVERLAPPEDPLUS* pOlp = NULL;
032    
033          pOlp = new OVERLAPPEDPLUS;
034          ZeroMemory(pOlp, sizeof(OVERLAPPEDPLUS));
035          pOlp->opCode = ioType;
036    
037          return pOlp;
038    }
039    
040    //分配连接进入的客户的相关信息
041    LPCLIENTCONTEXT CIOCPServer::AllocateContext()
042    {
043          LPCLIENTCONTEXT lpContext = NULL;
044    
045          lpContext = new CLIENTCONTEXT;
046          ZeroMemory(lpContext, sizeof(CLIENTCONTEXT));
047          lpContext->m_wsaBuffer.buf = lpContext->m_Buffer;
048          lpContext->m_wsaBuffer.len = BUFSIZE;
049    
050          return lpContext;
051    }
052    
053    //释放overlappedplus
054    void CIOCPServer::FreeOverlappedPlus(LPOVERLAPPEDPLUS lpOlp)
055    {
056          delete lpOlp;
057    }
058    
059    //根据消息overlapped的类型,处理消息,返回值TRUE:继续读,FALSE,不读
060    //一般写事件就不让他都返回FALSE,没有必要再读了!
061    BOOL CIOCPServer::ProcessIOMessage(SOCKET_STYPE stype,IOType opCode, LPCLIENTCONTEXT lpContext , DWORD dwIoSize)
062    {
063          BOOL bRet = FALSE;
064    
065          //根据stype确定操作
066          switch (stype)
067          {
068          case LOAD_SOCKET:
069               ProcessLoadMsg(lpContext);
070               break;
071          }
072    
073          return TRUE;
074    }
075    
076    //关闭完成端口
077    void CIOCPServer::CloseCompletionPort( )
078    {
079          PostQueuedCompletionStatus(m_hIocp, 0, (DWORD) NULL, NULL);
080    
081          // Close the CompletionPort and stop any more requests
082          CloseHandle(m_hIocp);
083    
084    }
085    
086    void CIOCPServer::CreateWorkerThread()
087    {
088          SYSTEM_INFO sysinfo;
089          DWORD dwThreadId;
090    
091          //在completion port上等待的线程数为:CPU*2+2
092          GetSystemInfo(&sysinfo);
093          m_dwThreads = sysinfo.dwNumberOfProcessors*2+2;
094    
095          for(UINT i=0;i  {
096              HANDLE hThread;
097              hThread = CreateThread(NULL,
098                  0,
099                  CompletionWorkerThread,
100                  (LPVOID)this,
101                  0,
102                  &dwThreadId);
103              CloseHandle(hThread);
104          }
105    
106          //产生完成端口
107          m_hIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
108          if(m_hIocp == NULL)
109          {
110               return;
111          }
112    }
113    
114    //绑定在端口上工作线程
115    DWORD WINAPI CIOCPServer::CompletionWorkerThread( void * lpParam)
116    {
117          CIOCPServer *pIocpServer = (CIOCPServer *)lpParam;
118    
119          DWORD dwNumRead;
120          LPCLIENTCONTEXT lpContext;
121          LPWSAOVERLAPPED lpOverlapped;
122          LPOVERLAPPEDPLUS lpOlp;
123    
124          while (TRUE)
125          {
126               BOOL bError = FALSE;
127               BOOL bEnterRead = TRUE;
128    
129               BOOL bResult = GetQueuedCompletionStatus(pIocpServer->m_hIocp,
130                    &dwNumRead,
131                    (LPDWORD)&lpContext,
132                    &lpOverlapped,
133                    INFINITE);
134    
135               //获得LPOVERLAPPEDPLUS指针
136               lpOlp = CONTAINING_RECORD(lpOverlapped, OVERLAPPEDPLUS, ol);
137    
138               if (dwNumRead == 0) {
139                   return 0;
140                }
141               //非timeout引起的错误, 相关信息没有从GetQueuedCompletionStatus中返回
142               if (!bResult && lpOlp == NULL && WAIT_TIMEOUT != WSAGetLastError())
143               {
144                    // 发生错误
145                   bError = TRUE;
146               }
147               //错误,但是相关信息从GetQueuedCompletionStatus中返回
148               //可能原因之一是:客户强制退出了!
149               else if(!bResult && lpOlp != NULL)
150               {
151                    //循环继续,不应该读了!
152                    continue;
153               }
154    
155               //无错误,处理事件
156               if (!bError)
157               {
158                     if(bResult && NULL != lpOlp && NULL != lpContext)
159                    {
160                         bEnterRead = pIocpServer->ProcessIOMessage(lpContext->m_stype,lpOlp->opCode, lpContext, dwNumRead);
161                    }
162              }
163    
164               //重新初试化
165               if(! bError && bEnterRead)
166               {
167                    LPOVERLAPPEDPLUS lpOlp = pIocpServer->AllocateOverlappedPlus(OP_IORead);
168                    ULONG ulFlags = MSG_PARTIAL;
169    
170                    ZeroMemory(lpContext->m_wsaBuffer.buf, lpContext->m_wsaBuffer.len);
171                    int len = sizeof(sockaddr_in);
172                   UINT nRetVal = WSARecvFrom(lpContext->m_Socket,
173                         &lpContext->m_wsaBuffer,
174                         1,
175                         0,
176                         &ulFlags,
177                         (sockaddr*)&lpContext->m_fromaddr,&len,
178                         &lpOlp->ol,
179                         NULL);
180    
181                    if ( nRetVal == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
182                    return FALSE;
183    
184               }
185    
186               pIocpServer->FreeOverlappedPlus(lpOlp);
187    
188          }
189          return 0;
190    }
191    
192    BOOL CIOCPServer::InitSocket(SOCKET_STYPE stype,int port,int num)
193    {
194          //bind SOCKET to completion port and init first work
195          LPCLIENTCONTEXT LoadListenData = AllocateContext();
196          if (LoadListenData == NULL)
197          return FALSE;
198    
199          LoadListenData->m_Socket = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_IP, NULL, 0, WSA_FLAG_OVERLAPPED);
200          if(LoadListenData->m_Socket == SOCKET_ERROR)
201          return FALSE;
202    
203          //需要绑定的本地地址
204          sockaddr_in local;
205          memset(&local, 0, sizeof(local));
206          local.sin_addr.s_addr = htonl(INADDR_ANY);
207          local.sin_family = AF_INET;
208          local.sin_port = htons(port);
209    
210          //绑定,将监听端口绑定到本地地址
211          if(bind(LoadListenData->m_Socket, (sockaddr*)&local,sizeof(local))
212          == SOCKET_ERROR)
213          return FALSE;
214    
215          LoadListenData->m_stype = stype;
216          LoadListenData->m_nNum = num;
217          HANDLE hrc =        CreateIoCompletionPort((HANDLE)LoadListenData>m_Socket,m_hIocp,(DWORD)LoadListenData,0);
218          if (NULL == hrc)
219          return FALSE;
220    
221          int len = sizeof(sockaddr_in);
222    
223          LPOVERLAPPEDPLUS lpOlp = AllocateOverlappedPlus(OP_IORead);
224          ULONG ulFlags = MSG_PARTIAL;
225    
226          int iret = WSARecvFrom(LoadListenData->m_Socket,
227               &(LoadListenData->m_wsaBuffer),
228               1,NULL,
229               &ulFlags,
230               (sockaddr*)&LoadListenData->m_fromaddr,&len,
231               &lpOlp->ol,
232               NULL
233          );
234          if (iret == SOCKET_ERROR && WSAGetLastError() != ERROR_IO_PENDING)
235          return FALSE;
236    
237          return TRUE;
238    }
239    
240    BOOL CIOCPServer::StartServer()
241    {
242          m_Database.OpenEx("DSN=SASSYSTEM;UID=;PWD=");
243          CreateWorkerThread();
244          if(!InitSocket(LOAD_SOCKET,14688))
245          AfxMessageBox("fair");
246          return TRUE;
247    }
248    
249    BOOL CIOCPServer::StopServer()
250    {
251    
252          CloseCompletionPort();
253          return TRUE;
254    }
255    
256    BOOL CIOCPServer::ProcessLoadMsg(LPCLIENTCONTEXT lpContext)
257    {
258    
259         //lpContext->m_Buffer就是你接收到的数据信息了
260    
         //调试信息
     
             return TRUE;
  }
 
献花( 0)
+1
分享到:分享到QQ空间分享到新浪微博分享到腾讯微博分享到搜狐微博
  • 推荐给朋友
  • 举报
(本文系 江南兰亭馆首藏   源文网址)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值