在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;
}