Linux安全网 - Linux操作系统_Linux 命令_Linux教程_Linux黑客

会员投稿 投稿指南 本期推荐:
搜索:
您的位置: Linux安全网 > Linux编程 > » 正文

完成端口IOCP之TCP服务器

来源: 未知 分享至:

        继续之前的异步重叠的系列,本文实践的为TCPSrv的完成端口实现,之前文章中层提到过该概念,也是被奉为WINDOWS SOCKET编程的最优解。但是否真的是最优,本文没测试,很多东西,个人认为看情形用远比抱着一个什么最好的情结更实用。

         依旧的风格,直接上代码,至于想捣鼓IOCP的人,看完整篇的代码也应该懂了。我还是相信代码以及运行结果远比一本书的文字来的有说服力。当然我的代码中必要的注释都还是存在的,以协助说明思路。

         编写主体前准备工作:

View Code   1 #include <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 MyTcpSrv;
 19 
 20 // 客户端套接字元
 21 typedef 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         memcpy(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         memset(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 _terminal_info
 80 {
 81     string                    s_ip;                            // IP地址
 82     USHORT                    s_uPort;                        // 端口号
 83     // 重载<运算符,以支持作为map的key
 84     friend inline bool operator < (const _terminal_info &lsconst _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>        VClnt;                // 客户端信息列表
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_LocalAddr;                    // 本地终端地址
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(22), &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, 0sizeof(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, 00)) == 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)_beginthreadex(NULL, 0, ServerWorkerThread, this0, &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, this0, &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, 0sizeof(SOCKADDR_IN)\
122             + 16sizeof(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, 0sizeof(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] = {123456789101112131415};
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, 050);
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

Tags:
分享至:
最新图文资讯
1 2 3 4 5 6
验证码:点击我更换图片 理智评论文明上网,拒绝恶意谩骂 用户名:
关于我们 - 联系我们 - 广告服务 - 友情链接 - 网站地图 - 版权声明 - 发展历史