TCPSrv.cpp 11 KB

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