继续之前的异步重叠的系列,本文实践的为TCPSrv的完成端口实现,之前文章中层提到过该概念,也是被奉为WINDOWS SOCKET编程的最优解。但是否真的是最优,本文没测试,很多东西,个人认为看情形用远比抱着一个什么最好的情结更实用。
依旧的风格,直接上代码,至于想捣鼓IOCP的人,看完整篇的代码也应该懂了。我还是相信代码以及运行结果远比一本书的文字来的有说服力。当然我的代码中必要的注释都还是存在的,以协助说明思路。
编写主体前准备工作:

View Code
1 #i
nclude <afxtempl.h>
2 #include
"winsock2.h"
3 #include <Mswsock.h>
4 #include <list>
5 #include <vector>
6 #include <
string>
7 #include <process.h>
8 #include <
time.h>
9 #include <map>
10
11 #include
"iostream"
12 using namespace std;
13
14 #define SOCKET_BUF_SIZE 10240
// 发送、接收缓冲区最大长度,10K
15 #define OVERLAPPED_DELIVER_SEND 0
// 发送数据
16 #define OVERLAPPED_DELIVER_RECV 2
// 接收数据
17
18 class MyT
cpSrv;
19
20 // 客户端套接字元
21 typ
edef
struct _CLIENT_ELEMENT
22 {
23 SOCKET s_socket;
// 客户端SOCKET套接字
24 SOCKADDR_IN s_clientInfo;
// 客户端终端信息
25 time_t s_tVisitTM;
// 访问时间
26 bool s_bFirstFrame;
// 第一帧标志位
27
28 _CLIENT_ELEMENT()
29 {
30 s_socket = INVALID_SOCKET;
31 }
32 } TS_CLIENT_ELEMENT, * LPTS_CLIENT_ELEMENT;
33
34 // 通信载体,此处使用尾随参数的解决思路,故而OVERLAPPED必须为第一个参数
35 typedef
struct _SOCKET_INFORMATION
36 {
37 OVERLAPPED s_overlapped;
38 CHAR s_buffer[SOCKET_BUF_SIZE];
// 存储接收的字符
39 int s_nBufLen;
// 接收的长度
40 WSABUF s_dataBuf;
// 接收缓冲区,为OS自动填充区
41 LPTS_CLIENT_ELEMENT s_lpClientElement;
// 客户端套接字元
42 UINT s_uDeliverType;
// 异步请求类型
43 int s_uAntiSendSize;
// 预期发送字节数
44 bool s_bIsDiscard;
// 作废标志位
45 MyTcpSrv* s_pThis;
// 所有者
46
47 _SOCKET_INFORMATION()
48 {
49 s_lpClientElement = NULL;
50 s_pThis = NULL;
51 }
52 } SOCKET_INFORMATION, * LPSOCKET_INFORMATION;
53
54 // TCPSrv、UDP网络报文数据结构
55 typedef
struct _netPara
56 {
57 UCHAR s_szBuf[SOCKET_BUF_SIZE];
// 数据缓存
58 WORD s_wBufLen;
// 数据长度
59
60 // 追加字符
61 void Append(_netPara* pNet)
62 {
63 me
mcpy(s_szBuf + s_wBufLen,pNet->s_szBuf,min(SOCKET_BUF_SIZE - s_wBufLen, pNet->s_wBufLen));
64 s_wBufLen += pNet->s_wBufLen;
65 }
66 // 释放
67 void Release(UINT uSize)
68 {
69 UCHAR szBuf[SOCKET_BUF_SIZE];
70 memcpy(szBuf, s_szBuf + uSize, s_wBufLen - uSize);
71 mem
set(s_szBuf,
0, SOCKET_BUF_SIZE);
72 memcpy(s_szBuf, szBuf, s_wBufLen - uSize);
73 s_wBufLen = s_wBufLen - uSize;
74 }
75 }SNetPara, * LPNetPara;
76
77
78 // 终端信息结构
79 typedef
struct _te
rminal_info
80 {
81 string s_ip;
// IP地址
82 USHORT s_uPort;
// 端口号
83 // 重载<运算符,以支持作为map的key
84 friend inline
bool operator < (
const _terminal_info &
ls,
const _terminal_info &rs);
85 friend inline
bool operator == (
const _terminal_info &ls,
const _terminal_info &rs);
86 }TERMINAL_INFO, * LPTERMINAL_INFO;
87
88 // LESS
89 bool operator < (
const _terminal_info& ls,
const _terminal_info& rs)
90 {
91 return (ls.s_ip < rs.s_ip || (ls.s_ip == rs.s_ip && ls.s_uPort < rs.s_uPort));
92 }
93
94 // EQUAL
95 bool operator == (
const _terminal_info& ls,
const _terminal_info& rs)
96 {
97 return (ls.s_ip == rs.s_ip && ls.s_uPort == rs.s_uPort);
98 }
99
100 typedef vector<TS_CLIENT_ELEMENT> VC
lnt;
// 客户端信息列表
101 typedef list<SNetPara> LNetPara;
// 接收信息列表
102
103 typedef map<TERMINAL_INFO, SNetPara> MNetDatagram;
// 网络数据包
主体结构设计:

View Code 1 // TCP服务器端
2 class MyTcpSrv
3 {
4 private:
5 CRITICAL_SECTION m_csLock;
// 临界对象,冲突锁
6 7 HANDLE m_hIOCP;
// 完成端口句柄
8 9 SOCKADDR_IN m_LocalA
ddr;
// 本地终端地址
10 SOCKET m_sLinstenSocket;
// 侦听套接字
11 HANDLE m_hListenThread;
// 侦听线程
12 UINT m_nListenThreadId;
// 侦听线程ID
13 HANDLE m_hListenEventExit;
// 侦听线程退出事件对象,用于退出侦听线程时通知子线程关闭
14 SYSTEM_INFO m_sysInfo;
// 系统信息,其中包含处理器等信息
15 VClnt m_clntList;
// 客户端清单
16 MNetDatagram m_netParaMap;
// 接收信息列表
17 18 public:
19 MyTcpSrv()
20 {
21 InitializeCriticalSection(&m_csLock);
22 m_hIOCP = INVALID_HANDLE_VALUE;
23 m_sLinstenSocket = INVALID_SOCKET;
24 m_hListenThread = INVALID_HANDLE_VALUE;
25 m_hListenEventExit = INVALID_HANDLE_VALUE;
26 }
27 ~MyTcpSrv()
28 {
29 DeleteCriticalSection(&m_csLock);
30 }
31 32 private:
33 // 加载SOCK DLL
34 bool LoadSock();
35 36 // 设置本地终端
37 bool SetLocalAddr(WORD nPort,
const char *szAddr);
38 39 // 初始化完成端口
40 bool InitialIOCP();
41 42 // 设置侦听套接字
43 bool SetupListenSocket();
44 45 // 投递接收请求
46 void DeliverRecv(LPSOCKET_INFORMATION lpInfo);
47 48 // 投递发送请求
49 void DeliverSend(LPSOCKET_INFORMATION lpInfo);
50 51 // 启动侦听线程
52 bool RunListenThread();
53 54 // 侦听例程
55 UINT
static WINAPI TCPListenThreadProc(LPVOID pParam);
56 57 // 工作例程
58 UINT
static WINAPI ServerWorkerThread(LPVOID CompletionPortID);
59 60 // 擦除记录
61 void Erase(LPSOCKET_INFORMATION lpSocketInfo);
62 63 // 解析获取的数据
64 void OnRecvData(LPSOCKET_INFORMATION lpSocketInfo);
65 66 // 停止侦听
67 void StopListening();
68 69 // 断开与指定客户端连接
70 void DisconnectUser(SOCKADDR_IN clientAddr);
71 72 // 断开与所有用户连接
73 void DisconnectAllUsers();
74 75 // 卸载SOCKDLL
76 void UnloadSock();
77 78 public:
79 // 创建通道
80 bool Create(LPTERMINAL_INFO pInfo);
81 82 // 关闭通道
83 void Close();
84 85 // 读取数据
86 int Read(
byte byRecv[], UINT uMaxSize, LPTERMINAL_INFO pInfo);
87 88 // 发送数据
89 int Write(
byte bySend[], UINT uAntiSize, LPTERMINAL_INFO pInfo);
90 91 // 重置服务器
92 bool Reset();
93 94 // 获取客户端列表信息
95 VClnt GetClinetList()
96 {
97 return m_clntList;
98 }
99 };
主体中成员方法的实现:

View Code 1 #include
"TCPSrv.h" 2 3 // 加载SOCK DLL
4 bool MyTcpSrv::LoadSock()
5 {
6 WSADATA wsaData;
7 return WSAStartup(MAKEWORD(
2,
2), &wsaData) ==
0 ?
true :
false;
8 }
9 10 // 卸载SOCK DLL
11 void MyTcpSrv::UnloadSock()
12 {
13 WSACleanup();
14 }
15 16 // 设置本地终端
17 bool MyTcpSrv::SetLocalAddr(WORD nPort,
const char *szAddr)
18 {
19 memset(&m_LocalAddr,
0,
sizeof(SOCKADDR_IN));
20 m_LocalAddr.sin_family = AF_INET;
21 m_LocalAddr.sin_port = htons(nPort);
22 if(szAddr == NULL)
23 m_LocalAddr.sin_addr.s_addr = htonl(INADDR_ANY);
24 else 25 {
26 if((m_LocalAddr.sin_addr.s_addr = inet_addr(szAddr)) == INADDR_NONE)
27 {
28 HOSTENT *host = NULL;
29 host = gethostbyname(szAddr);
30 if(host == NULL)
31 return false;
32 CopyMemory(&m_LocalAddr.sin_addr, host->h_addr, host->h_length);
33 }
34 }
35 return true;
36 }
37 38 // 初始化完成端口
39 bool MyTcpSrv::InitialIOCP()
40 {
41 // 创建完成端口,其中第三个参数为零,表示完成端口最大同时支持CPU个线程
42 if ((m_hIOCP = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,
0,
0)) == NULL)
43 return false;
44 45 // 获取系统信息,计算所需工作线程数,创建工作线程
46 SYSTEM_INFO sysInfo;
47 GetSystemInfo(&sysInfo);
48 UINT ThreadID;
49 for(USHORT i =
0; i < sysInfo.dwNumberOfProcessors *
2 +
2; i++)
50 {
51 HANDLE hThread;
52 if((hThread = (HANDLE)_beginthread
ex(NULL,
0, ServerWorkerThread,
this,
0, &ThreadID)) == NULL)
53 return false;
//创建工作线程失败
54 CloseHandle(hThread);
55 }
56 return true;
57 }
58 59 // 设置侦听套接字
60 bool MyTcpSrv::SetupListenSocket()
61 {
62 // 创建侦听套接字
63 if ((m_sLinstenSocket = WSASocket(AF_INET, SOCK_STREAM,
0, NULL,
0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
64 return false;
// 创建侦听套接字失败
65
66 // 绑定端口
67 if (bind(m_sLinstenSocket, (PSOCKADDR) &m_LocalAddr,
sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
68 return false;
// 绑定端口失败
69
70 // 进入侦听被动模式,准备接收
71 if (listen(m_sLinstenSocket, SOMAXCONN) == SOCKET_ERROR)
72 return false;
// 侦听失败
73 74 return true;
75 }
76 77 // 启动侦听线程
78 bool MyTcpSrv::RunListenThread()
79 {
80 // 初始化信号
81 m_hListenEventExit = CreateEvent(NULL, TRUE, FALSE, NULL);
82 if((m_hListenThread = (HANDLE)_beginthreadex(NULL,
0, TCPListenThreadProc,
this,
0, &m_nListenThreadId)) == NULL)
83 {
84 closesocket(m_sLinstenSocket);
85 return false;
// 启动侦听线程失败
86 }
87 return true;
88 }
89 90 // 侦听执行体
91 UINT WINAPI MyTcpSrv::TCPListenThreadProc(LPVOID pParam)
92 {
93 // 接收套接字
94 TS_CLIENT_ELEMENT AcceptElement;
95 WSAEVENT wsaListenEvent;
96 OVERLAPPED ListenOverlapped;
97 CHAR szAcceptBuffer [
2 * (
sizeof(SOCKADDR_IN) +
16)];
98 DWORD dwBytesReceived;
99 LPSOCKADDR lpServerSockInfo;
100 LPSOCKADDR lpClientSockInfo;
101 int nServerAddrLen;
102 int nClientAddrLen;
103 LPSOCKET_INFORMATION lpSocketInfo;
104 MyTcpSrv* pthis;
105 106 pthis = (MyTcpSrv*)pParam;
107 wsaListenEvent = WSACreateEvent();
108 109 // 不断接收连接接入
110 while(
true)
111 {
112 ZeroMemory(&AcceptElement,
sizeof(TS_CLIENT_ELEMENT));
113 if ((AcceptElement.s_socket = WSASocket(AF_INET, SOCK_STREAM,
0, NULL,
0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
114 return 0L;
//创建套接字失败
115 116 ZeroMemory(&ListenOverlapped,
sizeof(WSAOVERLAPPED));
117 WSAResetEvent(wsaListenEvent);
118 ListenOverlapped.hEvent = wsaListenEvent;
119 120 // 异步接收套接字连接
121 if (!AcceptEx(pthis->m_sLinstenSocket, AcceptElement.s_socket, (PVOID)szAcceptBuffer,
0,
sizeof(SOCKADDR_IN)\
122 +
16,
sizeof(SOCKADDR_IN) +
16, &dwBytesReceived, &ListenOverlapped))
123 {
124 if (WSAGetLastError() != ERROR_IO_PENDING)
125 return 0L;
//接受套接字失败
126 }
127 128 // 等待AcceptEx返回
129 while(TRUE)
130 {
131 HANDLE hEvents[
2];
132 hEvents[
0] = ListenOverlapped.hEvent;
133 hEvents[
1] = pthis->m_hListenEventExit;
134 135 DWORD dwEventIndex = WSAWaitForMultipleEvents(
2, hEvents, FALSE, WSA_INFINITE, TRUE);
136 if (dwEventIndex == WSA_WAIT_FAILED)
137 return 0L;
// 异常
138 if ((dwEventIndex-WAIT_OBJECT_0) ==
1)
139 return 0L;
// 接到退出线程通知
140 141 if (dwEventIndex != WAIT_IO_COMPLETION)
142 break;
143 }
144 145 // 获取客户端详细信息,并登记
146 GetAcceptExSockaddrs(szAcceptBuffer,
0,
sizeof(SOCKADDR_IN) +
16,
sizeof(SOCKADDR_IN) +
16, \
147 &lpServerSockInfo, &nServerAddrLen, &lpClientSockInfo, &nClientAddrLen);
148 memcpy(&AcceptElement.s_clientInfo, lpClientSockInfo,
sizeof(sockaddr_in));
149 time(&AcceptElement.s_tVisitTM);
// 获取访问时间
150 AcceptElement.s_bFirstFrame = TRUE;
151 lpSocketInfo =
new SOCKET_INFORMATION;
// 创建通信载体
152 pthis->m_clntList.push_back(AcceptElement);
153 lpSocketInfo->s_lpClientElement = &(pthis->m_clntList.back());
154 lpSocketInfo->s_dataBuf.len = SOCKET_BUF_SIZE;
155 lpSocketInfo->s_dataBuf.buf = lpSocketInfo->s_buffer;
156 lpSocketInfo->s_nBufLen =
0;
157 lpSocketInfo->s_pThis = pthis;
158 159 // 将获取到的SOCKET绑定到完成端口
160 if (CreateIoCompletionPort((HANDLE)lpSocketInfo->s_lpClientElement->s_socket, lpSocketInfo->s_pThis->m_hIOCP, (DWORD)lpSocketInfo,
0) == NULL)
161 return 0L;
// 绑定完成端口失败
162
163 // 递交异步接收请求
164 lpSocketInfo->s_pThis->DeliverRecv(lpSocketInfo);
165 }
166 return 1L;
167 }
168 169 // 递交异步接收请求
170 void MyTcpSrv::DeliverRecv(LPSOCKET_INFORMATION lpSocketInfo)
171 {
172 DWORD dwRecvBytes =
0;
173 DWORD dwFlags =
0;
174 175 // 整理通信载体
176 ZeroMemory(&(lpSocketInfo->s_overlapped),
sizeof(WSAOVERLAPPED));
177 lpSocketInfo->s_dataBuf.len = SOCKET_BUF_SIZE;
178 lpSocketInfo->s_dataBuf.buf = lpSocketInfo->s_buffer;
179 lpSocketInfo->s_nBufLen =
0;
180 lpSocketInfo->s_pThis =
this;
181 lpSocketInfo->s_uDeliverType = OVERLAPPED_DELIVER_RECV;
182 183 if (WSARecv(lpSocketInfo->s_lpClientElement->s_socket, &(lpSocketInfo->s_dataBuf),
1, &dwRecvBytes, \
184 &dwFlags, &(lpSocketInfo->s_overlapped), NULL) == SOCKET_ERROR)
185 {
186 // 异步投递失败
187 if (WSAGetLastError() != WSA_IO_PENDING)
188 Erase(lpSocketInfo);
189 }
190 }
191 192 // 递交异步发送请求
193 void MyTcpSrv::DeliverSend(LPSOCKET_INFORMATION lpSocketInfo)
194 {
195 DWORD dwSendBytes =
0;
196 DWORD dwFlags =
0;
197 198 // 已经全部发送完毕
199 if (lpSocketInfo->s_uAntiSendSize - lpSocketInfo->s_nBufLen <=
0)
200 {
201 delete lpSocketInfo;
202 return;
203 }
204 205 // 整理通信载体
206 ZeroMemory(&(lpSocketInfo->s_overlapped),
sizeof(WSAOVERLAPPED));
207 lpSocketInfo->s_dataBuf.len = lpSocketInfo->s_uAntiSendSize - lpSocketInfo->s_nBufLen;
208 lpSocketInfo->s_dataBuf.buf = lpSocketInfo->s_buffer + lpSocketInfo->s_nBufLen;
209 lpSocketInfo->s_pThis =
this;
210 lpSocketInfo->s_uDeliverType = OVERLAPPED_DELIVER_SEND;
// 发送
211
212 // 异步发送请求
213 if(WSASend(lpSocketInfo->s_lpClientElement->s_socket, &lpSocketInfo->s_dataBuf,
1, &dwSendBytes, dwFlags, &lpSocketInfo->s_overlapped, NULL) == SOCKET_ERROR)
214 {
215 // 异步发送请求失败
216 if (WSAGetLastError() != WSA_IO_PENDING)
217 {
218 delete lpSocketInfo;
// 释放通信载体
219 return;
220 }
221 }
222 }
223 224 // 擦除记录
225 void MyTcpSrv::Erase(LPSOCKET_INFORMATION lpSocketInfo)
226 {
227 // 关闭连接
228 closesocket(lpSocketInfo->s_lpClientElement->s_socket);
229 230 // 清除记录
231 EnterCriticalSection(&m_csLock);
232 VClnt::iterator ite;
233 for(ite=m_clntList.begin();ite != m_clntList.end();++ite)
234 {
235 if (ite->s_socket == lpSocketInfo->s_lpClientElement->s_socket)
236 {
237 m_clntList.erase(ite);
238 break;
239 }
240 }
241 LeaveCriticalSection(&m_csLock);
242 243 delete lpSocketInfo;
// 释放通信载体
244 }
245 246 // 工作例程
247 UINT WINAPI MyTcpSrv::ServerWorkerThread(LPVOID lpMyTcpSrv)
248 {
249 MyTcpSrv* pThis = (MyTcpSrv*)lpMyTcpSrv;
250 DWORD BytesTransferred;
251 DWORD dwInfo;
252 LPSOCKET_INFORMATION lpSocketInfo;
// 通信载体
253 //LPTS_CLIENT_ELEMENT lpClientInfo;
254 //lpSocketInfo = new SOCKET_INFORMATION;
255 while(TRUE)
256 {
257 BOOL bRes = GetQueuedCompletionStatus(pThis->m_hIOCP, &BytesTransferred, &dwInfo, (LPOVERLAPPED*)(&lpSocketInfo), INFINITE);
258 259 switch(lpSocketInfo->s_uDeliverType)
260 {
261 case OVERLAPPED_DELIVER_SEND:
262 // 完成端口异常或客户端关闭则不再尝试发送数据
263 if (!bRes || BytesTransferred ==
0)
264 {
265 delete lpSocketInfo;
// 释放通信载体
266 return 1L;
267 }
268 // 解析获取的数据
269 lpSocketInfo->s_nBufLen += BytesTransferred;
// 计算已发送总字节数
270 // 再次投递
271 lpSocketInfo->s_pThis->DeliverSend(lpSocketInfo);
272 break;
273 case OVERLAPPED_DELIVER_RECV:
274 // 完成端口异常,退出线程
275 if (!bRes)
276 {
277 pThis->Erase(lpSocketInfo);
278 return 1L;
279 }
280 // 客户端退出
281 if (BytesTransferred ==
0)
282 {
283 pThis->Erase(lpSocketInfo);
284 continue;
285 }
286 lpSocketInfo->s_nBufLen = BytesTransferred;
// 实际接收字节数
287 // 解析获取的数据
288 lpSocketInfo->s_pThis->OnRecvData(lpSocketInfo);
289 // 再次投递
290 lpSocketInfo->s_pThis->DeliverRecv(lpSocketInfo);
291 break;
292 default:
293 break;
294 }
295 }
296 }
297 298 // 获取数据完成处理
299 void MyTcpSrv::OnRecvData(LPSOCKET_INFORMATION lpSocketInfo)
300 {
301 SNetPara pNet;
302 memset(pNet.s_szBuf,
0, SOCKET_BUF_SIZE);
303 TERMINAL_INFO tInfo;
304 305 tInfo.s_ip = inet_ntoa(lpSocketInfo->s_lpClientElement->s_clientInfo.sin_addr);
306 tInfo.s_uPort = ntohs(lpSocketInfo->s_lpClientElement->s_clientInfo.sin_port);
307 308 memcpy(pNet.s_szBuf, lpSocketInfo->s_buffer, min(SOCKET_BUF_SIZE, lpSocketInfo->s_nBufLen));
309 pNet.s_wBufLen = lpSocketInfo->s_nBufLen;
310 311 EnterCriticalSection(&m_csLock);
312 std::pair<MNetDatagram::iterator,
bool> res = m_netParaMap.insert(std::make_pair(tInfo, pNet));
313 if (!res.second)
314 m_netParaMap[tInfo].Append(&pNet);
315 LeaveCriticalSection(&m_csLock);
316 }
317 318 // 停止侦听
319 void MyTcpSrv::StopListening()
320 {
321 SetEvent(m_hListenEventExit);
322 WaitForSingleObject(m_hListenThread, INFINITE);
// 等待侦听线程退出
323 DisconnectAllUsers();
324 CloseHandle(m_hIOCP);
325 m_hIOCP = INVALID_HANDLE_VALUE;
326 closesocket(m_sLinstenSocket);
327 m_sLinstenSocket = INVALID_SOCKET;
328 CloseHandle(m_hListenThread);
329 m_hListenThread = INVALID_HANDLE_VALUE;
330 CloseHandle(m_hListenEventExit);
331 m_hListenEventExit = INVALID_HANDLE_VALUE;
332 }
333 334 // 断开与指定用户的连接
335 void MyTcpSrv::DisconnectUser(SOCKADDR_IN clientAddr)
336 {
337 SOCKET clientSock = INVALID_SOCKET;
338 339 // 清除记录
340 EnterCriticalSection(&m_csLock);
341 VClnt::iterator ite = m_clntList.begin();
342 for(; ite!=m_clntList.end(); ++ite)
343 {
344 if (ite->s_clientInfo.sin_addr.s_addr== clientAddr.sin_addr.s_addr && ite->s_clientInfo.sin_port == clientAddr.sin_port)
345 {
346 m_clntList.erase(ite);
347 break;
348 }
349 }
350 LeaveCriticalSection(&m_csLock);
351 352 if(clientSock == INVALID_SOCKET)
353 return;
354 355 // 关闭套接字
356 shutdown(clientSock, SD_BOTH);
357 closesocket(clientSock);
358 }
359 360 // 断开与所有用户的连接
361 void MyTcpSrv::DisconnectAllUsers()
362 {
363 while (!m_clntList.empty())
364 DisconnectUser(m_clntList.front().s_clientInfo);
365 }
366 367 // 创建通道
368 bool MyTcpSrv::Create(LPTERMINAL_INFO pInfo)
369 {
370 return LoadSock() && SetLocalAddr(pInfo->s_uPort,pInfo->s_ip.c_str()) && InitialIOCP() && SetupListenSocket() && RunListenThread();
371 }
372 373 // 读取数据
374 int MyTcpSrv::Read(
byte byRecv[], UINT uMaxSize, LPTERMINAL_INFO pInfo)
375 {
376 UINT uSize =
0;
377 EnterCriticalSection(&m_csLock);
378 SNetPara& netPara = m_netParaMap[*pInfo];
379 uSize = min(netPara.s_wBufLen, uMaxSize);
380 memcpy(byRecv, netPara.s_szBuf , uSize);
381 netPara.Release(uSize);
382 LeaveCriticalSection(&m_csLock);
383 return uSize;
384 }
385 386 // 写入数据
387 int MyTcpSrv::Write(
byte bySend[], UINT uAntiSize, LPTERMINAL_INFO pInfo)
388 {
389 // 创建通信载体
390 LPSOCKET_INFORMATION lpSocketInfo =
new SOCKET_INFORMATION;
// 创建通信载体
391 // 查找客户端信息
392 EnterCriticalSection(&m_csLock);
393 VClnt::iterator ite = m_clntList.begin();
394 for (;ite!=m_clntList.end(); ++ite)
395 {
396 if (inet_ntoa(ite->s_clientInfo.sin_addr) == pInfo->s_ip && ntohs(ite->s_clientInfo.sin_port) == pInfo->s_uPort)
397 {
398 lpSocketInfo->s_lpClientElement = &(*ite);
399 break;
400 }
401 }
402 LeaveCriticalSection(&m_csLock);
403 404 if (lpSocketInfo->s_lpClientElement == NULL)
405 return 0;
// 不存在指定客户端
406 407 UINT uSize = min(SOCKET_BUF_SIZE, uAntiSize);
408 memcpy(lpSocketInfo->s_buffer, bySend, uSize);
409 lpSocketInfo->s_nBufLen =
0;
410 lpSocketInfo->s_pThis =
this;
411 lpSocketInfo->s_uAntiSendSize = uSize;
412 413 // 递交发送请求
414 DeliverSend(lpSocketInfo);
415 return uSize;
416 }
417 418 // 重置服务器
419 bool MyTcpSrv::Reset()
420 {
421 StopListening();
422 return InitialIOCP() && SetupListenSocket() && RunListenThread();
423 }
424 425 // 关闭服务器
426 void MyTcpSrv::Close()
427 {
428 StopListening();
429 }
测试代码:

View Code 1 int _tmain(
int argc, _TCHAR* argv[])
2 {
3 MyTcpSrv tcp;
4 TERMINAL_INFO localInfo;
5 localInfo.s_ip =
"127.0.0.1";
6 localInfo.s_uPort =
9000;
7 tcp.Create(&localInfo);
8 9 byte szRead[
50];
10 byte szWrite[
15] = {
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15};
11 int rdSize =
50;
12 int wrSize =
15;
13 VClnt::iterator ite;
14 int rdAcu =
0;
15 int wrAcu =
0;
16 TERMINAL_INFO tInfo;
17 int i =
10;
18 while(i--)
19 {
20 Sleep(
3000);
21 22 if (tcp.GetClinetList().size()==
0)
23 {
24 Sleep(
1000);
25 }
26 VClnt temp = tcp.GetClinetList();
27 for(ite = temp.begin(); ite != temp.end(); ++ite)
28 {
29 tInfo.s_ip = inet_ntoa(ite->s_clientInfo.sin_addr);
30 tInfo.s_uPort=ntohs(ite ->s_clientInfo.sin_port);
31 tInfo.s_uPort++;
32 memset(szRead,
0,
50);
33 rdAcu = tcp.Read(szRead, rdSize, &tInfo);
34 wrAcu = tcp.Write(szWrite, wrSize, &tInfo);
35 36 cout<<
"接收数据 源地址"<<tInfo.s_ip.c_str()<<
":"<<tInfo.s_uPort<<
"数据长度:"<<rdAcu<<
"数据内容:";
37 for (
int i =
0; i < rdAcu; i++)
38 cout<<hex<<(
int)(szRead[i])<<
" ";
39 cout<<
'\n';
40 41 cout<<
"发送数据 目的地址"<<tInfo.s_ip.c_str()<<
":"<<tInfo.s_uPort<<
"数据长度:"<<wrAcu<<
"数据内容:";
42 for (
int i =
0; i < wrAcu; i++)
43 cout<<hex<<(
int)(szWrite[i])<<
" ";
44 cout<<
'\n';
45 }
46 }
47 48 tcp.Close();
49 return 0;
50 }
源码下载地址:http://download.csdn.net/detail/fryhunter/3823012