socketmodel.cpp
上传用户:swkcbjrc
上传日期:2016-04-02
资源大小:45277k
文件大小:30k
源码类别:

游戏

开发平台:

Visual C++

  1. // DPEventSocket.cpp: implementation of the CSocketModel class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "SocketModel.h"
  6. #ifdef _DEBUG
  7. #undef THIS_FILE
  8. static char THIS_FILE[]=__FILE__;
  9. #define new DEBUG_NEW
  10. #endif
  11. //////////////////////////////////////////////////////////////////////
  12. // Construction/Destruction
  13. //////////////////////////////////////////////////////////////////////
  14. CSocketModel::CSocketModel()
  15. {
  16. ::InitializeCriticalSection(&m_csErrorNo);
  17. }
  18. CSocketModel::~CSocketModel()
  19. {
  20. ::DeleteCriticalSection(&m_csErrorNo);
  21. }
  22. // 设置套接字是否为阻塞的
  23. //入口:套接字,是否需要阻塞的
  24. //出口:如果正确那么返回0,错误返回-1
  25. int CSocketModel::BlockSocket(SOCKET hSocket, BOOL bBlock/*FALSE*/)
  26. {
  27. u_long IoctlLong = (bBlock) ? 0 : 1;
  28. if (ioctlsocket(hSocket, FIONBIO, &IoctlLong) == SOCKET_ERROR)
  29. {
  30. SetLastError( WSAGetLastError() );
  31. return (SOCKET_ERROR);
  32.     }
  33. return (SOCKET_SUCCESS);
  34. }
  35. //设置套接字属性
  36. //入口:套接字
  37. //出口:如果正确那么返回0,错误返回-1
  38. int CSocketModel::SetSocketOption(SOCKET hSocket)
  39. {
  40.     int nActivate = 1;
  41. //允许地址重用
  42.     if (setsockopt(hSocket, SOL_SOCKET, SO_REUSEADDR, (const char *) &nActivate,
  43. sizeof(nActivate)) == SOCKET_ERROR )
  44.     {
  45.         SetLastError( WSAGetLastError() );
  46.         return (SOCKET_ERROR);//return (-1)
  47.     }
  48. //  如果支持,设置KEEPALIVE属性 (这样做会带来其他不良后果)
  49. //setsockopt(hSocket, SOL_SOCKET, SO_KEEPALIVE, (const char *) &nActivate,sizeof(iActivate));
  50. return (SOCKET_SUCCESS);
  51. }
  52. //接收所有数据,注意在这个函数调用之前必须确认是否有接收消息到来
  53. //入口:套接字,数据缓冲区,缓冲区大小
  54. //出口:如果正确那么返回接收的字节数量,错误返回错误代码
  55. //注意:这里使用的是WINSOCK2的专有WSARecv()函数进行接收,所以为非阻塞模式
  56. //     所以调用此函数前必须确认有数据到来的消息,否则返回错误
  57. int CSocketModel::RecvLL(SOCKET hSocket, char *pszBuffer, int nBufferSize)
  58. {
  59. DWORD dwRtxBytes = 0,
  60. dwRtxFlags = 0;
  61. WSABUF WSABuff;
  62. //清空缓冲
  63. ZeroMemory(&WSABuff,sizeof(WSABUF));
  64. WSABuff.len = nBufferSize;
  65. WSABuff.buf = pszBuffer;
  66. //如果正确就返回本次接收的字节个数,如果错误返回错误号码(负数)
  67. return ((WSARecv(hSocket, &WSABuff, 1, &dwRtxBytes, &dwRtxFlags,NULL, NULL) 
  68. == SOCKET_SUCCESS) ? (int) dwRtxBytes : -WSAGetLastError());
  69. }
  70. int CSocketModel::RecvData_Block(SOCKET hSocket, char *pszBuffer, int nBufferSize, 
  71. DWORD dwTimeout)
  72. {
  73. ASSERT(hSocket != NULL);
  74. if(hSocket==NULL)
  75. return ( SOCKET_ERROR );
  76. FD_SET fd = {1, hSocket};
  77. TIMEVAL tv = {dwTimeout, 0};
  78. int nBytesReceived=0;
  79. if(select(0, &fd, NULL, NULL, &tv) == 0) 
  80. goto CLEAR;
  81. if((nBytesReceived = recv(hSocket, pszBuffer, nBufferSize, 0)) == SOCKET_ERROR)
  82. goto CLEAR;
  83. return nBytesReceived;
  84. CLEAR:
  85. SetLastError(WSAGetLastError());//超时
  86. return(SOCKET_ERROR);
  87. }
  88. // 接收数据(阻塞直至收到数据为止)
  89. //入口:套接字,缓冲区,缓冲区大小,超时
  90. //注意:这个函数只管理一个端口的接收信息需求,所以这里的EventSelect不能一起管理64
  91. //     个端口的信息
  92. int CSocketModel::RecvData_Event(SOCKET hSocket, char *pszBuffer, 
  93.    int nBufferSize, DWORD dwTimeout)
  94. {
  95. HANDLE hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  96. if (hReadEvent == NULL)
  97. {
  98. SetLastError( (int)GetLastError() );
  99. return ( SOCKET_ERROR );
  100. }
  101. int nRecvBytes = 0;
  102. DWORD dwWaitResult ;
  103. for (;;)
  104. {
  105. // 注册FD_READ | FD_CLOSE 事件 
  106. // (因为可能在等待FD_READ事件中,对方关闭套接字,所以要关注FD_CLOSE)
  107. if( WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, FD_READ | FD_CLOSE) 
  108. == SOCKET_ERROR)
  109. {
  110. CloseHandle(hReadEvent);
  111. SetLastError( WSAGetLastError() );
  112. return (SOCKET_ERROR);
  113. }
  114. // 等等FD_READ | FD_CLOSE事件的发生
  115. dwWaitResult = WSAWaitForMultipleEvents(1, &hReadEvent, TRUE,dwTimeout, TRUE);
  116. if (dwWaitResult != WSA_WAIT_EVENT_0)
  117. {
  118. // 清除事件
  119. WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
  120. CloseHandle(hReadEvent);
  121. SetLastError( WSAGetLastError() );
  122. return (SOCKET_ERROR);
  123. }
  124. ////////////////////////////////////////////////////////////// 
  125. /// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
  126. /// 进一步检查网络是否发生错误
  127. ///////////////////////////////////////////////////////////////
  128. WSANETWORKEVENTS NetEvent;
  129. if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hReadEvent,&NetEvent) == SOCKET_ERROR)
  130. {
  131. // 清除事件
  132. WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
  133. CloseHandle(hReadEvent);
  134. SetLastError( WSAGetLastError() );
  135. return (SOCKET_ERROR);
  136. }
  137. //判断发生了什么事件 FD_READ 或 FD_CLOSE
  138. if( ( NetEvent.lNetworkEvents == FD_CLOSE ) ||
  139.  ( NetEvent.lNetworkEvents == FD_READ && 
  140.    NetEvent.iErrorCode[FD_READ_BIT] !=0 ) ) // 发生错误
  141. {
  142. // 清除事件
  143. WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
  144. CloseHandle(hReadEvent);
  145. SetLastError(WSAGetLastError() );
  146. return (SOCKET_ERROR);
  147. }
  148. ////////////////////////////////////////////////////////////////
  149. // 清除事件
  150. WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
  151. // 接收数据
  152. if ((nRecvBytes = RecvLL(hSocket, pszBuffer, nBufferSize)) >= 0)
  153. break; // 跳出循环
  154. //Recv返回的是错误代码的负数,所以需要调转过来
  155. int nErrorCode = -nRecvBytes;
  156. if ( nErrorCode != WSAEWOULDBLOCK ) //太多的未完成重叠操作
  157. {
  158. CloseHandle(hReadEvent);
  159. SetLastError( nErrorCode );
  160. return (SOCKET_ERROR);
  161. }
  162. //阻塞住了
  163. ////////////////////////////////////////////////////////////////////////
  164. //  如果发生阻塞,就等待一定时间后重试,以免CPU轮询浪费时间
  165. ////////////////////////////////////////////////////////////////////////
  166. Sleep(_BLOCKED_SNDRCV_SLEEP);
  167.     }
  168.     CloseHandle(hReadEvent);
  169.     return (nRecvBytes);
  170. }
  171. int CSocketModel::RecvDataFrom_Block( SOCKET hSocket, struct sockaddr * pFrom, 
  172. int nAddrlen,char *pszBuffer, int nBufferSize,
  173. DWORD dwTimeout)
  174. {
  175. ASSERT(hSocket != NULL);
  176. if(hSocket==NULL)
  177. return (SOCKET_ERROR);
  178. FD_SET fd = {1, hSocket};
  179. TIMEVAL tv = {dwTimeout, 0};
  180. int nFromSize=0;
  181. int nBytesReceived=0;
  182. if(select(0, &fd, NULL, NULL, &tv) == 0) 
  183. goto CLEAR;
  184. nFromSize = nAddrlen;
  185. nBytesReceived = recvfrom(hSocket, pszBuffer, nBufferSize, 0, pFrom, &nFromSize);
  186. if(nBytesReceived == SOCKET_ERROR) 
  187. goto CLEAR;
  188. return nBytesReceived;
  189. CLEAR:
  190. SetLastError(WSAGetLastError());//超时
  191. return(SOCKET_ERROR);
  192. }
  193. // 数据报接收函数
  194. int CSocketModel::RecvDataFrom_Event( SOCKET hSocket, struct sockaddr * pFrom, 
  195.    int nAddrlen,char *pszBuffer, 
  196.    int nBufferSize,DWORD dwTimeout)
  197. {
  198. HANDLE hReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  199. if (hReadEvent == NULL)
  200. {
  201. SetLastError((int)GetLastError() );
  202. return (SOCKET_ERROR);
  203. }
  204. DWORD dwRtxBytes = 0,
  205. dwRtxFlags = 0;
  206. WSABUF WSABuff;
  207. ZeroMemory(&WSABuff,sizeof(WSABUF));
  208. WSABuff.len = nBufferSize;
  209. WSABuff.buf = pszBuffer;
  210. for (;;)
  211. {
  212. // 注册FD_READ事件
  213. if( WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, FD_READ) 
  214. == SOCKET_ERROR)
  215. {
  216. CloseHandle(hReadEvent);
  217. SetLastError(  WSAGetLastError() );
  218. return (SOCKET_ERROR);
  219. }
  220. DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hReadEvent, 
  221. TRUE,dwTimeout, TRUE);
  222. if( dwWaitResult != WSA_WAIT_EVENT_0 )
  223. {
  224. // 注销事件
  225. WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
  226. CloseHandle(hReadEvent);
  227. SetLastError( WSAGetLastError());
  228. return (SOCKET_ERROR);
  229. }
  230. ////////////////////////////////////////////////////////////// 
  231. /// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
  232. /// 进一步检查网络是否发生错误
  233. ///////////////////////////////////////////////////////////////
  234. WSANETWORKEVENTS NetEvent;
  235. if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hReadEvent,&NetEvent)
  236. == SOCKET_ERROR)
  237. {
  238. // 注销事件
  239. WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
  240. CloseHandle(hReadEvent);
  241. SetLastError( WSAGetLastError() );
  242. return (SOCKET_ERROR);
  243. }
  244. if(NetEvent.iErrorCode[FD_READ_BIT] !=0 ) // 发生错误
  245. {
  246. // 注销事件
  247. WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
  248. CloseHandle(hReadEvent);
  249. SetLastError(NetEvent.iErrorCode[FD_READ_BIT]);
  250. return (SOCKET_ERROR);
  251. }
  252. ////////////////////////////////////////////////////////////////
  253. // 注销事件
  254. WSAEventSelect(hSocket, (WSAEVENT) hReadEvent, 0);
  255. int FromLen = nAddrlen;
  256. if ( WSARecvFrom(hSocket, &WSABuff, 1, &dwRtxBytes, 
  257. &dwRtxFlags,pFrom, &FromLen, NULL, NULL) == SOCKET_SUCCESS )
  258. break;
  259. if ( WSAGetLastError() != WSAEWOULDBLOCK)
  260. {
  261. CloseHandle(hReadEvent);
  262. SetLastError( WSAGetLastError() );
  263. return (SOCKET_ERROR);
  264. }
  265. ///////////////////////////////////////////////////////////////////////////
  266. // 睡眠一段时间
  267. //////////////////////////////////////////////////////////////////////////
  268. Sleep(_BLOCKED_SNDRCV_SLEEP);
  269. }
  270. CloseHandle(hReadEvent);
  271. return ((int) dwRtxBytes);
  272. }
  273. //发送数据,阻塞
  274. //入口:套接字,发送的字串,字串长度,超时值
  275. //出口:正确返回发送的字节数量,错误返回SOCKET_ERROR
  276. int CSocketModel::Send_Block(SOCKET hSocket,char const * pszBuffer, 
  277. int nBufferSize, DWORD dwTimeout)
  278. {
  279. ASSERT(hSocket!=NULL);
  280. if(hSocket==NULL||pszBuffer==NULL)
  281. return (SOCKET_ERROR);
  282. FD_SET fd = {1, hSocket};
  283. TIMEVAL tv = {dwTimeout, 0};
  284. int nBytesSent=0;
  285. if(select(0, NULL, &fd, NULL, &tv) == 0)
  286. goto CLEAR;//选择发送超时
  287. if((nBytesSent = send(hSocket, pszBuffer, nBufferSize, 0)) == SOCKET_ERROR) 
  288. goto CLEAR;//发送出错误
  289. return nBytesSent;
  290. CLEAR:
  291. SetLastError(WSAGetLastError());//超时
  292. return(SOCKET_ERROR);
  293. }
  294. //发送全部缓冲区中数据,阻塞
  295. //入口:套接字,发送的字串,字串长度,超时值
  296. //出口:正确返回发送的字节数量,错误返回SOCKET_ERROR
  297. int CSocketModel::SendData_Block(SOCKET hSocket,char const * pszBuffer, 
  298. int nBufferSize, DWORD dwTimeout)
  299. {
  300. if(hSocket==NULL)
  301. return(SOCKET_ERROR);
  302. int nBytesSent = 0;
  303. int nBytesThisTime;
  304. const char* pszTemp = pszBuffer;
  305. do {
  306. nBytesThisTime = Send_Block(hSocket,pszTemp, nBufferSize-nBytesSent, dwTimeout);
  307. if(nBytesThisTime<0)
  308. return(SOCKET_ERROR);
  309. //如果一次没有发送成功
  310. nBytesSent += nBytesThisTime;
  311. //改变当前字符指针
  312. pszTemp += nBytesThisTime;
  313. } while(nBytesSent < nBufferSize);
  314. return nBytesSent;
  315. }
  316. // 发送数据
  317. //入口:套接字,发送缓冲区,大小,超时
  318. //出口:返回一次发送数据的字节数量,如果错误返回SOCKET_ERROR
  319. int CSocketModel::Send_Event(SOCKET hSocket, char const * pszBuffer, 
  320.    int nBufferSize, DWORD dwTimeout)
  321. {
  322. HANDLE hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  323. if (hWriteEvent == NULL)
  324. {
  325. SetLastError( (int)GetLastError() );
  326. return (SOCKET_ERROR);
  327. }
  328. int nSendBytes = 0;
  329. for (;;)
  330. {
  331. ////////////////////////////////////////////////////////////////
  332. // 发送数据成功
  333. if ((nSendBytes = SendLL(hSocket, pszBuffer, nBufferSize)) >= 0)
  334. break;
  335. //如果发送的字节数量小于0证明出错
  336. int nErrorCode = -nSendBytes;
  337. //如果是WSAEWOULDBLOCK错误,证明在该端口上仍然进行着其他I/O操作
  338. //所以我们下面进行必要的等待循环处理
  339. if (nErrorCode != WSAEWOULDBLOCK)
  340. {
  341. CloseHandle(hWriteEvent);
  342. SetLastError( WSAGetLastError() );
  343. return (SOCKET_ERROR);
  344. }
  345. ///////////////////////////////////////////////////////////////////////////////
  346. //  睡眠一段时间
  347. ///////////////////////////////////////////////////////////////////////////////
  348. Sleep(_BLOCKED_SNDRCV_SLEEP);
  349. // 注册FD_WRITE | FD_CLOSE 事件
  350. if( WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, FD_WRITE|FD_CLOSE) 
  351. == SOCKET_ERROR)
  352. {
  353. CloseHandle(hWriteEvent);
  354. SetLastError( WSAGetLastError() );
  355. return (SOCKET_ERROR);
  356. }
  357. // 等待事件发生
  358. DWORD dwWaitResult = WSAWaitForMultipleEvents(1, 
  359. &hWriteEvent, TRUE,dwTimeout, TRUE);
  360. if (dwWaitResult != WSA_WAIT_EVENT_0)
  361. {
  362. // 清除网络事件
  363. WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
  364. CloseHandle(hWriteEvent);
  365. SetLastError( WSAGetLastError() );
  366. return (SOCKET_ERROR);
  367. }
  368. ////////////////////////////////////////////////////////////// 
  369. /// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
  370. /// 进一步检查网络是否发生错误
  371. ///////////////////////////////////////////////////////////////
  372. WSANETWORKEVENTS NetEvent;
  373. if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hWriteEvent,&NetEvent) == SOCKET_ERROR)
  374. {
  375.    // 清除网络事件
  376. WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
  377. CloseHandle(hWriteEvent);
  378. SetLastError( WSAGetLastError() );
  379. return (SOCKET_ERROR);
  380. }
  381. if( ( NetEvent.lNetworkEvents == FD_CLOSE ) ||
  382.  ( NetEvent.lNetworkEvents == FD_WRITE   &&
  383. NetEvent.iErrorCode[FD_WRITE_BIT] !=0 ) ) // 发生错误
  384. {
  385. // 清除网络事件
  386. WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
  387. CloseHandle(hWriteEvent);
  388. SetLastError( WSAGetLastError() );
  389. return (SOCKET_ERROR);
  390. }
  391. // 清除网络事件
  392. WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
  393.    }
  394.     CloseHandle(hWriteEvent);
  395.     return (nSendBytes);
  396. }
  397. //发送完所有数据或超时
  398. //入口:套接字,缓冲区,缓冲区大小,超时
  399. //出口:返回已经发送的字节个数或SOCKET_ERROR
  400. int CSocketModel::SendData_Event(SOCKET hSocket, char const * pszBuffer, 
  401.  int nBufferSize, DWORD dwTimeout)
  402. {
  403. int nRtxBytes = 0;
  404. int nRtxCurrent = 0;
  405. while (nRtxBytes < nBufferSize)
  406. {
  407. nRtxCurrent = Send_Event(hSocket, (pszBuffer + nRtxBytes),
  408. (nBufferSize - nRtxBytes), dwTimeout);
  409. if (nRtxCurrent < 0)
  410. return (nRtxBytes);
  411. nRtxBytes += nRtxCurrent;
  412. }
  413. return (nRtxBytes);
  414. }
  415. //一次发送数据,但不一定全部都发送
  416. //入口:套接字,接收方地址信息,地址结构,结构长度,缓冲区,缓冲区长度,超时
  417. //出口:正确返回发送字节数量,错误返回SOCKET_ERROR
  418. int CSocketModel::SendTo_Block(SOCKET hSocket, const struct sockaddr * pTo,
  419. int nAddrLen,char const * pszBuffer, int nBufferSize, DWORD dwTimeout)
  420. {
  421. if(hSocket==NULL||pszBuffer==NULL)
  422. return SOCKET_ERROR;
  423. FD_SET fd = {1, hSocket};
  424. TIMEVAL tv = {dwTimeout, 0};
  425. int nBytesSent=0;
  426. if(select(0, NULL, &fd, NULL, &tv) == 0) 
  427. goto CLEAR;
  428. nBytesSent = sendto(hSocket, pszBuffer, nBufferSize, 0, pTo, nAddrLen);
  429. if(nBytesSent == SOCKET_ERROR)
  430. goto CLEAR;
  431. return nBytesSent;
  432. CLEAR:
  433. SetLastError(WSAGetLastError());//超时
  434. return(SOCKET_ERROR);
  435. }
  436. // 数据报发送数据报
  437. int CSocketModel::SendTo_Event(SOCKET hSocket, const struct sockaddr * pTo,
  438.  int nAddrLen,char const * pszBuffer, 
  439.  int nBufferSize, DWORD dwTimeout)
  440. {
  441. HANDLE hWriteEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  442. if (hWriteEvent == NULL)
  443. {
  444. SetLastError( (int)GetLastError() );
  445. return (SOCKET_ERROR);
  446. }
  447. DWORD dwRtxBytes = 0,
  448.             dwRtxFlags = 0;
  449. WSABUF WSABuff;
  450. ZeroMemory(&WSABuff,sizeof(WSABUF));
  451. WSABuff.len = nBufferSize;
  452. WSABuff.buf = (char *) pszBuffer;
  453. for (;;)
  454. {
  455. if (WSASendTo( hSocket, &WSABuff, 1, &dwRtxBytes, dwRtxFlags,
  456. pTo, nAddrLen, NULL, NULL) == SOCKET_SUCCESS)
  457. break;
  458. if (WSAGetLastError() != WSAEWOULDBLOCK)
  459. {
  460. CloseHandle(hWriteEvent);
  461. SetLastError(  WSAGetLastError() );
  462. return (SOCKET_ERROR);
  463. }
  464. //////////////////////////////////////////////////////////////////////////
  465. // 睡眠一段时间
  466. /////////////////////////////////////////////////////////////////////////
  467. Sleep(_BLOCKED_SNDRCV_SLEEP);
  468. // 注册FD_WRITE事件  
  469. if( WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, FD_WRITE) 
  470. == SOCKET_ERROR)
  471. {
  472. CloseHandle(hWriteEvent);
  473. SetLastError( WSAGetLastError() );
  474. return (SOCKET_ERROR);
  475. }
  476. DWORD dwWaitResult = WSAWaitForMultipleEvents
  477. (1, &hWriteEvent, TRUE,dwTimeout, TRUE);
  478. if( dwWaitResult != WSA_WAIT_EVENT_0 )
  479. {
  480. // 注销事件
  481. WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
  482. CloseHandle(hWriteEvent);
  483. SetLastError(  WSAGetLastError() );
  484. return (SOCKET_ERROR);
  485. }
  486. ////////////////////////////////////////////////////////////// 
  487. /// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
  488. /// 进一步检查网络是否发生错误
  489. ///////////////////////////////////////////////////////////////
  490. WSANETWORKEVENTS NetEvent;
  491. if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hWriteEvent,&NetEvent) 
  492. == SOCKET_ERROR)
  493. {
  494. // 注销事件
  495. WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
  496. CloseHandle(hWriteEvent);
  497. SetLastError(  WSAGetLastError() );
  498. return (SOCKET_ERROR);
  499. }
  500. if(NetEvent.iErrorCode[FD_WRITE_BIT] !=0 ) // 发生错误
  501. {
  502. // 注销事件
  503. WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
  504. CloseHandle(hWriteEvent);
  505. SetLastError(NetEvent.iErrorCode[FD_WRITE_BIT]);
  506. return (SOCKET_ERROR);
  507. }
  508. ////////////////////////////////////////////////////////////////
  509. // 注销事件
  510. WSAEventSelect(hSocket, (WSAEVENT) hWriteEvent, 0);
  511. }
  512. CloseHandle(hWriteEvent);
  513. return ((int) dwRtxBytes);
  514. }
  515. //一次性发送数据(事件IO)
  516. //入口:套接字,缓冲区,缓冲区长度
  517. //出口:正确-返回发送的字节数量,错误-返回错误代码的负数
  518. int CSocketModel::SendLL(SOCKET hSocket, char const * pszBuffer, 
  519.  int nBufferSize)
  520. {
  521. DWORD dwRtxBytes = 0;
  522. WSABUF WSABuff;
  523. ZeroMemory(&WSABuff,sizeof(WSABUF));
  524. WSABuff.len = nBufferSize;
  525. WSABuff.buf = (char *) pszBuffer;
  526. return ((WSASend(hSocket, &WSABuff, 1, &dwRtxBytes, 0,NULL, NULL)
  527. == SOCKET_SUCCESS) ? (int) dwRtxBytes : -WSAGetLastError());
  528. }
  529. //关闭套接字
  530. //入口:套接字,是否强行关闭(如果bHardClose==FALSE,那么接收剩余的数据后关闭连接)
  531. //注意:这里的接收剩余数据只是为了让SERVER将数据发送操作执行完毕
  532. //     所以接收的剩余数据不可用
  533. void CSocketModel::CloseSocket(SOCKET hSocket, BOOL bHardClose)
  534. {
  535. // 不需要捕获错误
  536. if (!bHardClose) // 优雅关闭 Graceful close
  537. {
  538. // 不再发送数据,对于TCP套接字,在所有的数据都发送完毕之后,
  539. // 将发送一个 FIN ,通知接收方所有数据已经发送完毕。
  540. shutdown(hSocket, SD_SEND);
  541. // 接收缓冲区有可能还有未接收的数据,在关闭套接字之前应该先
  542. // 读取残留的数据。
  543. int nRecvResult;
  544. HANDLE hSocketEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  545. //为残留数据提供的缓冲区
  546. char szBuffer[256];
  547. do
  548. {
  549. if (hSocketEvent != NULL)
  550. {
  551. //注册网络事件
  552. WSAEventSelect(hSocket, (WSAEVENT) hSocketEvent, FD_READ | FD_CLOSE);
  553. WSAWaitForMultipleEvents(1, &hSocketEvent, TRUE,_SHUTDOWN_RECV_TIMEOUT, TRUE);
  554. //清除网络事件
  555. WSAEventSelect(hSocket, (WSAEVENT) hSocketEvent, 0);
  556. }
  557. ZeroMemory(szBuffer,256);
  558. //接收残留数据
  559. nRecvResult = RecvLL(hSocket, szBuffer, sizeof(szBuffer));
  560. } while (nRecvResult > 0);
  561. if (hSocketEvent != NULL)
  562. CloseHandle(hSocketEvent);
  563. //不再允许接收和发送
  564. shutdown(hSocket, SD_BOTH);
  565. }
  566. // 关闭套接字
  567. closesocket(hSocket);
  568. }
  569. //接受套接字连接
  570. //入口:侦听端口号,本地地址
  571. //出口:返回一个可用的套接字或INVALID_SOCKET
  572. //注意:如果为阻塞等待,就是在DWTIMEOUT的时间设置为无限的时候
  573. //     如果我们关闭该套接字会出现的问题
  574. SOCKET CSocketModel::Accept_Event(SOCKET hSocket, struct sockaddr * pSocketAddress, 
  575.    int *nAddrLen,DWORD dwTimeout
  576.    /*= DP_DEFAULT_TIMEOUT*/)
  577. {
  578. HANDLE hAcceptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  579. if (hAcceptEvent == NULL)
  580. {
  581. SetLastError( (int)GetLastError() );
  582. return (INVALID_SOCKET);
  583. }
  584. //异步事件选择
  585. // 注册FD_ACCEPT事件
  586. if( WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, FD_ACCEPT) == SOCKET_ERROR)
  587. {
  588. CloseHandle(hAcceptEvent);
  589. SetLastError( WSAGetLastError() );
  590. return (INVALID_SOCKET);
  591. }
  592. //进行非阻塞接收
  593. SOCKET hSocketAccept = WSAAccept(hSocket, pSocketAddress, nAddrLen, NULL, 0);
  594. int nConnectError = WSAGetLastError();
  595. //如果返回的端口是没有定义的,并且接收的错误码为"代决"状态
  596. if ((hSocketAccept == INVALID_SOCKET) && (nConnectError == WSAEWOULDBLOCK))
  597. {
  598. //阻塞,这个函数如果正确返回那么我们在使用WSAACCEPT重新接收一次,
  599. //就可以获得用户的SOCKET
  600. //因为这个函数返回代表ACCPETEVENT成为传信状态,如果网络没有错误那么
  601. //代表有用户的正确端口接入
  602. DWORD dwWaitResult = WSAWaitForMultipleEvents
  603. (1,&hAcceptEvent,TRUE,dwTimeout,TRUE);
  604. if (dwWaitResult == WSA_WAIT_EVENT_0)
  605. {
  606. ////////////////////////////////////////////////////////////// 
  607. /// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
  608. /// 进一步检查网络是否发生错误
  609. ///////////////////////////////////////////////////////////////
  610. WSANETWORKEVENTS NetEvent;
  611. if(WSAEnumNetworkEvents(hSocket,hAcceptEvent,&NetEvent) == SOCKET_ERROR)
  612. SetLastError( WSAGetLastError() );
  613. else if(NetEvent.iErrorCode[FD_ACCEPT_BIT] !=0 ) // 发生错误
  614. SetLastError( NetEvent.iErrorCode[FD_ACCEPT_BIT] );
  615. else
  616. //接收到真正的用户SOCKET
  617. hSocketAccept = WSAAccept(hSocket, pSocketAddress, nAddrLen, NULL, 0);
  618. }
  619. else
  620. SetLastError(WSAGetLastError());
  621. }
  622. // 注销网络事件
  623. WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, 0);
  624. CloseHandle(hAcceptEvent);
  625. if (hSocketAccept != INVALID_SOCKET)
  626. {
  627. // 设置套接字的属性为地址可重用并且为非阻塞的
  628. if ((BlockSocket(hSocketAccept, 0)  == SOCKET_ERROR ) ||
  629. (SetSocketOption(hSocketAccept) == SOCKET_ERROR ) )
  630. {
  631. CloseSocket(hSocketAccept,TRUE);
  632. return (INVALID_SOCKET);
  633. }
  634. }
  635. return (hSocketAccept);
  636. }
  637. // 接受套接字连接(允许中断)
  638. //入口:结束事件,其他入口都和Accept一样
  639. //出口:返回一个可用的套接字或INVALID_SOCKET
  640. //注意:超时值默认为DP_DEFAULT_TIMEOUT,如果结束事件没有的话,
  641. //     那么跟调用上面的函数没有区别
  642. SOCKET CSocketModel::AcceptEx_Event(SOCKET hSocket, struct sockaddr * pSocketAddress, 
  643.   int *nAddrLen,HANDLE hEndEvent,DWORD dwTimeout 
  644.   /*= DP_DEFAULT_TIMEOUT*/)
  645. {
  646. if( hEndEvent == NULL)
  647. return Accept_Event(hSocket,pSocketAddress,nAddrLen,dwTimeout);
  648. HANDLE hAcceptEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  649. if (hAcceptEvent == NULL)
  650. {
  651. SetLastError( (int)GetLastError() );
  652. return (INVALID_SOCKET);
  653. }
  654. WSAEVENT hEvent[2]; 
  655. hEvent[0] = (WSAEVENT)hAcceptEvent;
  656. hEvent[1] = (WSAEVENT)hEndEvent;
  657. // 注册FD_ACCEPT事件
  658. if( WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, FD_ACCEPT) == SOCKET_ERROR)
  659. {
  660. CloseHandle(hAcceptEvent);
  661. SetLastError( WSAGetLastError() );
  662. return (INVALID_SOCKET);
  663. }
  664. SOCKET hSocketAccept = WSAAccept(hSocket, pSocketAddress, nAddrLen, NULL, 0);
  665. int    nConnectError = WSAGetLastError();
  666. if ((hSocketAccept == INVALID_SOCKET) && (nConnectError == WSAEWOULDBLOCK))
  667. {
  668. // 阻塞,等待两个事件,如果其中一个发生那么我们向下继续执行
  669. //所以这意味着指定结束事件后,如果程序想中断ACCEPT的执行
  670. //那么就激活该结束事件,程序将按照错误一样的处理
  671. DWORD dwWaitResult = WSAWaitForMultipleEvents(2, hEvent, FALSE,dwTimeout, TRUE);
  672. if (dwWaitResult == WSA_WAIT_EVENT_0)
  673. {
  674. ////////////////////////////////////////////////////////////// 
  675. /// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
  676. /// 进一步检查网络是否发生错误
  677. ///////////////////////////////////////////////////////////////
  678. WSANETWORKEVENTS NetEvent;
  679. if(WSAEnumNetworkEvents(hSocket,hAcceptEvent,&NetEvent) == SOCKET_ERROR)
  680. SetLastError(WSAGetLastError());
  681. else if(NetEvent.iErrorCode[FD_ACCEPT_BIT] !=0 ) // 发生错误
  682. SetLastError( NetEvent.iErrorCode[FD_ACCEPT_BIT] );
  683. else
  684. hSocketAccept = WSAAccept(hSocket, pSocketAddress, nAddrLen, NULL, 0);
  685. }
  686. else
  687. SetLastError( WSAGetLastError() );
  688. }
  689. // 注销网络事件
  690. WSAEventSelect(hSocket, (WSAEVENT) hAcceptEvent, 0);
  691. CloseHandle(hAcceptEvent);
  692. if (hSocketAccept != INVALID_SOCKET)
  693. {
  694. // 设置套接字的属性为地址可重用并且为非阻塞的
  695. if ((BlockSocket(hSocketAccept, 0) < 0) ||
  696. (SetSocketOption(hSocketAccept) < 0) )
  697. {
  698. CloseSocket(hSocketAccept,TRUE);
  699. return (INVALID_SOCKET);
  700. }
  701. }
  702. return (hSocketAccept);
  703. }
  704. //阻塞ACCEPT,没有响应不返回
  705. //入口:套接字,主机地址,长度
  706. //出口:正确返回端口号,否则返回INVALID_SOCKET
  707. SOCKET CSocketModel::Accept_Block(SOCKET hSocket, struct sockaddr * pSocketAddress,
  708. int *nAddrLen)
  709. {
  710. ASSERT(hSocket!=NULL);
  711. //int nLengthAddr = sizeof(SOCKADDR);
  712. SOCKET hAccept = accept(hSocket, pSocketAddress, nAddrLen);
  713. //如果该端口错误
  714. if(hAccept == INVALID_SOCKET) {
  715. SetLastError(WSAGetLastError());
  716. }
  717. return hAccept;
  718. }
  719. // 绑定套接字
  720. //入口:套接字,绑定的地址信息,长度
  721. //出口:正确0,错误-1
  722. int CSocketModel::BindSocket(SOCKET hSocket, struct sockaddr * pSocketAddress, 
  723. int nAddrLen)
  724. {
  725. if (bind(hSocket, pSocketAddress, nAddrLen) == SOCKET_ERROR)
  726. {
  727. SetLastError( WSAGetLastError() );
  728. return (SOCKET_ERROR);
  729. }
  730. return (SOCKET_SUCCESS);
  731. }
  732. // 绑定套接字
  733. //入口:套接字,端口号
  734. //出口:正确0,错误-1
  735. //注意:这个函数不同于上个函数,调用这个函数只需要给定一个端口号
  736. //     至于地址信息在函数内部默认处理(本机IP的该端口)
  737. int CSocketModel::BindSocketEx(SOCKET hSocket,int nPort)
  738. {
  739. SOCKADDR_IN sockAddr;
  740. ZeroMemory(&sockAddr,sizeof(sockAddr));
  741. sockAddr.sin_family = AF_INET;
  742. sockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  743. sockAddr.sin_port = htons((u_short)nPort);
  744. return BindSocket(hSocket,(SOCKADDR *)&sockAddr, sizeof(sockAddr));
  745. }
  746. //释放Winsock2动态连接库
  747. //入口:无
  748. //出口:无
  749. void CSocketModel::CleanupLibrary(void)
  750. {
  751.     WSACleanup();
  752. }
  753. //注册WINSOCK2.2DLL
  754. //入口:无
  755. //出口:无
  756. int CSocketModel::InitLibrary(void)
  757. {
  758. WSADATA         WSD;
  759. WORD wVersionRequired = MAKEWORD( _SOCKET_MAJOR_VERSION,_SOCKET_MINOR_VERSION );
  760. ZeroMemory(&WSD,sizeof(WSADATA));
  761. int nErrorNo = WSAStartup(wVersionRequired, &WSD);
  762. if ( SOCKET_SUCCESS != nErrorNo )
  763. {
  764. SetLastError( nErrorNo );
  765. return ( SOCKET_ERROR );
  766. }
  767. if ( LOBYTE( WSD.wVersion ) != _SOCKET_MINOR_VERSION ||
  768.  HIBYTE( WSD.wVersion ) != _SOCKET_MAJOR_VERSION ) 
  769. {
  770. WSACleanup( );
  771. SetLastError( WSAVERNOTSUPPORTED );
  772. return (SOCKET_ERROR); 
  773. }
  774. //成功初始化
  775. return (SOCKET_SUCCESS);
  776. }
  777. // 建立连接
  778. //入口:套接字,地址结构,结构长度,超时
  779. //出口:SOCKET_SUCCESS/SOCKET_ERROR
  780. int CSocketModel::Connect_Event(SOCKET hSocket, const struct sockaddr * pSocketAddress, 
  781.   int nAddrLen,DWORD dwTimeout)
  782. {
  783. HANDLE hConnectEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  784. if (hConnectEvent == NULL)
  785. {
  786. SetLastError( (int)GetLastError() );
  787. return (SOCKET_ERROR);
  788. }
  789. // 注册FD_CONNECT事件
  790. if( WSAEventSelect(hSocket, (WSAEVENT) hConnectEvent, FD_CONNECT) == SOCKET_ERROR)
  791. {
  792. CloseHandle(hConnectEvent);
  793. SetLastError( WSAGetLastError() );
  794. return (SOCKET_ERROR);
  795. }
  796. int nConnectResult = WSAConnect(hSocket, pSocketAddress, nAddrLen, 
  797. NULL, NULL, NULL, NULL);
  798. int nConnectError  = WSAGetLastError();
  799. if ((nConnectResult == SOCKET_ERROR) && (nConnectError == WSAEWOULDBLOCK))
  800. {
  801. DWORD dwWaitResult = WSAWaitForMultipleEvents(1, &hConnectEvent, 
  802. TRUE,dwTimeout, TRUE);
  803. if (dwWaitResult != WSA_WAIT_EVENT_0)
  804. {
  805. SetLastError( WSAGetLastError() );
  806. nConnectResult = SOCKET_ERROR;
  807. }
  808. else
  809. {
  810. ////////////////////////////////////////////////////////////// 
  811. /// 注意:即使 dwWaitResult == WSA_WAIT_EVENT0 ,也应该 
  812. /// 进一步检查网络是否发生错误
  813. ///////////////////////////////////////////////////////////////
  814. WSANETWORKEVENTS NetEvent;
  815. if(WSAEnumNetworkEvents(hSocket,(WSAEVENT)hConnectEvent,&NetEvent) 
  816. == SOCKET_ERROR)
  817. {
  818. SetLastError( WSAGetLastError() );
  819. nConnectResult = SOCKET_ERROR;
  820. }
  821. else if(NetEvent.iErrorCode[FD_CONNECT_BIT] !=0 ) // 发生错误
  822. {
  823. SetLastError( NetEvent.iErrorCode[FD_CONNECT_BIT] );
  824. nConnectResult = SOCKET_ERROR;
  825. }
  826. else
  827. nConnectResult = SOCKET_SUCCESS;
  828. ////////////////////////////////////////////////////////////////
  829. }
  830. }
  831. // 注销网络事件
  832. WSAEventSelect(hSocket, (WSAEVENT) hConnectEvent, 0);
  833. CloseHandle(hConnectEvent);
  834. return (nConnectResult);
  835. }
  836. int CSocketModel::Connect_Block(SOCKET hSocket, const struct sockaddr * pSocketAddress, 
  837. int nAddrLen)
  838. {
  839. ASSERT(hSocket!=NULL);
  840. if(hSocket==NULL)
  841. return SOCKET_ERROR;
  842. if(connect(hSocket, pSocketAddress, nAddrLen) == SOCKET_ERROR) 
  843. return SOCKET_ERROR;
  844. return SOCKET_SUCCESS;
  845. }
  846. //创建具有重叠IO能力的套接字
  847. //入口:协议,协议类型(TCP/UDP),协议
  848. //出口:返回创建的重叠IO SOCKET
  849. //注意:使用SOCKET()函数创建的套接字默认具有重叠IO能力
  850. SOCKET CSocketModel::CreateSocket(int nAddressFamily /*= AF_INET*/, 
  851.   int nType/*= SOCK_STREAM*/,
  852.   int nProtocol/*= 0*/)
  853. {
  854. SOCKET hSocket = WSASocket(nAddressFamily, nType, nProtocol, 
  855. NULL,0,WSA_FLAG_OVERLAPPED);
  856. if ( hSocket == INVALID_SOCKET )
  857. {
  858. SetLastError( WSAGetLastError() );
  859. return (INVALID_SOCKET);
  860. }
  861. //设置套接字选项
  862. if ( SOCKET_ERROR == SetSocketOption(hSocket) ) //设置属性失败
  863. {
  864. CloseSocket(hSocket, TRUE);
  865. return (INVALID_SOCKET);
  866. }
  867. return (hSocket);
  868. }
  869. //引入该函数的目的是为了避免NT下对域名解析的CACHE造成的问题
  870. //入口:无
  871. //出口:返回主机IP,或者INADDR_NONE
  872. DWORD WINAPI DNSThread(  LPVOID pParam )
  873. {
  874. DWORD dwIP = INADDR_NONE;
  875. PHOSTENT pHost = gethostbyname( (char *)pParam );
  876. if(pHost == NULL)
  877. return INADDR_NONE;
  878. dwIP = inet_addr( inet_ntoa(*(IN_ADDR *)*pHost->h_addr_list) );
  879. return dwIP;
  880. }
  881. //取得一个指定名字或者IP字串的DWORD IP表示
  882. //入口:主机IP或者域名,是否启动新线程进行查找IP
  883. //出口:返回IP,或者INADDR_NONE
  884. DWORD CSocketModel::GetIP(const char* name,BOOL bFixNtDNS /* = FALSE*/)// Used to Fix NT DNS Problem
  885. {
  886. //这里是为了将字串IP直接转换成DWORD的形式
  887. DWORD dwIP = inet_addr(name);
  888. if( dwIP != INADDR_NONE )
  889. return dwIP;
  890. //如果传入的是服务器的域名则进行向下程序
  891. //如果NT的CATCH有问题,那么进入下面的模块,主要是启动新线程进行域名解析
  892. if( bFixNtDNS )
  893. {
  894. OSVERSIONINFO osVersion;
  895. osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  896. if( GetVersionEx(&osVersion) )
  897. {
  898. if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
  899. {
  900. DWORD dwThreadId = 0;
  901. HANDLE hThread = CreateThread(NULL,0,DNSThread,(LPVOID)name,0,&dwThreadId);
  902. if( hThread != NULL)
  903. {
  904. //注意这里在等待的不是一个事件,而是线程句柄
  905. WaitForSingleObject(hThread,INFINITE);
  906. //注意这里取得线程退出码就是我们需要的IP
  907. if( GetExitCodeThread(hThread,&dwIP))
  908. return dwIP;
  909. }
  910. }
  911. }
  912. }
  913. //取得主机信息
  914. PHOSTENT pHost = gethostbyname(name);
  915. if(pHost == NULL)
  916. return INADDR_NONE;
  917. dwIP = inet_addr( inet_ntoa(*(IN_ADDR *)*pHost->h_addr_list) );
  918. return dwIP;
  919. }
  920. // 监听套接字
  921. //入口:套接字,接入的等待队列长度
  922. //出口:SOCKET_ERROR/SOCKET_SUCCESS
  923. int CSocketModel::ListenSocket(SOCKET hSocket, int nConnections)
  924. {
  925. if(listen(hSocket, nConnections) == SOCKET_ERROR)
  926. {
  927. SetLastError( WSAGetLastError() );
  928. return (SOCKET_ERROR);
  929. }
  930. return (SOCKET_SUCCESS);
  931. }