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

游戏

开发平台:

Visual C++

  1. #include "StdAfx.h"
  2. #include "serversocket.h"
  3. #include "process.h"
  4. #define DATA_BUFSIZE 4096
  5. // 监听线程
  6. UINT ServerListenThread(LPVOID lParam)
  7. {
  8. LOGMESSAGE("服务器端监听中.....n");
  9. CServerSocket* pServer = (CServerSocket*)lParam;
  10. SOCKADDR_IN ClientAddr;                   // 定义一个客户端得地址结构作为参数
  11. int addr_length=sizeof(ClientAddr);
  12. while(TRUE)
  13. {
  14. if(pServer->dwEventTotal>=WSA_MAXIMUM_WAIT_EVENTS)  // 因为超出了Windows的最大等待事件数量
  15. {
  16. LOGMESSAGE("已达到最大连接数!");
  17. continue;
  18. }
  19. SOCKET sockTemp = WSAAccept(pServer->sockListen,(SOCKADDR*)&ClientAddr,&addr_length, NULL, 0); 
  20. if(sockTemp  == INVALID_SOCKET)
  21. {
  22. LOGMESSAGE("Accept Connection failed!");
  23. continue;
  24. }
  25. pServer->nSockIndex = pServer->GetEmptySocket();    // 从Socket数组中获得一个空闲的socket
  26. pServer->sockAcceptArray[pServer->nSockIndex] = sockTemp;
  27. // 这里可以取得客户端的IP和端口,但是我们只取其中的SOCKET编号
  28. LPCTSTR lpIP =  inet_ntoa(ClientAddr.sin_addr);
  29. UINT nPort = ClientAddr.sin_port;
  30. char strSock[80];
  31. sprintf(strSock,"New Client,SOCKET编号:%drn",pServer->sockAcceptArray[pServer->nSockIndex] );
  32. LOGMESSAGE(strSock);
  33. // 接收客户端连接以后,为每一个连入的SOCKET都初始化建立一个重叠结构
  34. pServer->Flags = 0;
  35. pServer->EventArray[pServer->nSockIndex] = WSACreateEvent();
  36. ZeroMemory(&pServer->AcceptOverlapped[pServer->nSockIndex],sizeof(WSAOVERLAPPED));
  37. char buffer[DATA_BUFSIZE];
  38. ZeroMemory(buffer,DATA_BUFSIZE);
  39. pServer->AcceptOverlapped[pServer->nSockIndex].hEvent = pServer->EventArray[pServer->nSockIndex]; // 关联事件
  40. pServer->DataBuf[pServer->nSockIndex].len = DATA_BUFSIZE;
  41. pServer->DataBuf[pServer->nSockIndex].buf = buffer;
  42. // 投递第一个WSARecv请求,以便开始在套接字上接受数据
  43. if(WSARecv(pServer->sockAcceptArray[pServer->nSockIndex] ,&pServer->DataBuf[pServer->nSockIndex],1,&pServer->dwRecvBytes,&pServer->Flags,
  44. & pServer->AcceptOverlapped[pServer->nSockIndex] ,NULL) == SOCKET_ERROR)
  45. {
  46. if(WSAGetLastError() != WSA_IO_PENDING)    
  47. {
  48. // 返回WSA_IO_PENDING是正常情况,表示IO操作正在进行,不能立即完成
  49. // 如果不是WSA_IO_PENDING错误,就表示操作失败了
  50. LOGMESSAGE("错误:第一次投递Recv操作失败!!此套接字将被关闭!");
  51. closesocket(pServer->sockAcceptArray[pServer->nSockIndex]);
  52. pServer->sockAcceptArray[pServer->nSockIndex] = INVALID_SOCKET;
  53. WSACloseEvent(pServer->EventArray[pServer->nSockIndex]);
  54. continue;
  55. }
  56. }
  57. pServer->dwEventTotal ++;
  58. }
  59. return 0;
  60. }
  61. // 重叠I/O处理线程
  62. UINT OverlappedThread(LPVOID lParam)
  63. {
  64. CServerSocket* pServer = (CServerSocket*)lParam;
  65. while(pServer->bOverlapped)                    // 循环检测事件数组中的事件,并对接收的数据进行处理:)
  66. {
  67. DWORD dwIndex;
  68. // 等候重叠I/O调用结束
  69. // 因为我们把事件和Overlapped绑定在一起,重叠操作完成后我们会接到事件通知
  70. dwIndex = WSAWaitForMultipleEvents(pServer->dwEventTotal,pServer->EventArray,FALSE,INFINITE,FALSE);
  71. if(dwIndex == WSA_WAIT_TIMEOUT)
  72. continue;
  73. if(dwIndex == WSA_WAIT_FAILED)  // 出现监听错误
  74. {
  75. Sleep(200);
  76. continue;
  77. }
  78. // 取得索引值,得知事件的索引号
  79. dwIndex = dwIndex - WSA_WAIT_EVENT_0;
  80. // 获得索引号以后,这个事件已经没有利用价值,重置之
  81. WSAResetEvent(pServer->EventArray[dwIndex]);
  82. // 然后确定当前索引号的SOCKET的重叠请求状态
  83. DWORD dwBytesTransferred;
  84. WSAOVERLAPPED& CurrentOverlapped = pServer->AcceptOverlapped[dwIndex]; // 这里纯粹为了减少代码长度,付给了一个临时变量
  85. SOCKET& sockCurrent = pServer->sockAcceptArray[dwIndex] ;  // 同上
  86. WSAGetOverlappedResult(sockCurrent,&CurrentOverlapped ,
  87. &dwBytesTransferred,FALSE,&pServer->Flags);
  88. // 先检查通信对方是否已经关闭连接
  89. // 如果==0则表示连接已经,则关闭套接字
  90. if(dwBytesTransferred == 0)
  91. {
  92. char strSock[80];
  93. sprintf(strSock,"Client disconnect:SOCKET编号:%drn",pServer->sockAcceptArray[dwIndex] );
  94. LOGMESSAGE(strSock);
  95. closesocket(sockCurrent);
  96. sockCurrent = INVALID_SOCKET;
  97. //WSACloseEvent( EventArray[dwIndex] );
  98. pServer->dwEventTotal--;
  99. continue;
  100. }
  101. // DataBuf中包含接收到的数据,我们发到对话框中给予显示
  102. char strSock[80];
  103. sprintf(strSock,"Socket data SOCKET编号:%d,%srn",sockCurrent,pServer->DataBuf[dwIndex].buf);
  104. LOGMESSAGE(strSock);
  105. // 然后在套接字上投递另一个WSARecv请求(不要晕,注意看,代码和前面第一次WSARecv一样^_^)
  106. pServer->Flags = 0;
  107. ZeroMemory(&CurrentOverlapped,sizeof(WSAOVERLAPPED));
  108. char buffer[DATA_BUFSIZE];
  109. ZeroMemory(buffer,DATA_BUFSIZE);
  110. CurrentOverlapped.hEvent = pServer->EventArray[dwIndex];
  111. pServer->DataBuf[dwIndex].len = DATA_BUFSIZE;
  112. pServer->DataBuf[dwIndex].buf = buffer;
  113. // 开始另外一个WSARecv
  114. if(WSARecv(sockCurrent,&pServer->DataBuf[dwIndex],1,&pServer->dwRecvBytes,&pServer->Flags,
  115. &CurrentOverlapped ,NULL) == SOCKET_ERROR)
  116. {
  117. if(WSAGetLastError() != WSA_IO_PENDING) 
  118. {
  119. LOGMESSAGE("错误:投递Recv操作失败!!此套接字将被关闭!");
  120. closesocket(sockCurrent);
  121. sockCurrent = INVALID_SOCKET;
  122. WSACloseEvent(pServer->EventArray[dwIndex]);
  123. pServer->dwEventTotal--;
  124. continue;
  125. }
  126. }
  127. }
  128. return 0;
  129. }
  130. CServerSocket::CServerSocket(void)
  131. {
  132. for(int i=0;i<WSA_MAXIMUM_WAIT_EVENTS;i++)   // 初始化SOCKET
  133. {
  134. sockAcceptArray[i] = INVALID_SOCKET;
  135. }
  136. dwEventTotal=0;
  137. dwRecvBytes=0;
  138. Flags=0;
  139. nSockIndex = 0;
  140. bOverlapped = FALSE;
  141. }
  142. CServerSocket::~CServerSocket(void)
  143. {
  144. LOGMESSAGE("CServerSocket 析构!");
  145. WSACleanup();
  146. }
  147. int CServerSocket::InitWSASocket()
  148. {
  149. //init socket
  150. WSADATA     WSD;
  151. WORD wVersionRequired = MAKEWORD( 2,2 );
  152. ZeroMemory(&WSD,sizeof(WSADATA));
  153. int nErrorNo = WSAStartup(wVersionRequired, &WSD);
  154. return nErrorNo;
  155. }
  156. // 这些都是固定套路了,没有区别
  157. int CServerSocket::StartListening(const UINT& port)
  158. {
  159. m_nPort = port;
  160. int nRet;
  161. InitWSASocket();
  162. sockListen = WSASocket(AF_INET,SOCK_STREAM,0, NULL, 0,WSA_FLAG_OVERLAPPED);         //创建服务套接字(流式)
  163. //server_socket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,WSA_FLAG_OVERLAPPED);
  164. SOCKADDR_IN ServerAddr;                                       //分配端口及协议族并绑定
  165. ServerAddr.sin_family=AF_INET;                                
  166. ServerAddr.sin_addr.S_un.S_addr  =htonl(INADDR_ANY);          
  167. ServerAddr.sin_port=htons(port);
  168. nRet=bind(sockListen,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr)); // 绑定套接字
  169. if(nRet==SOCKET_ERROR)
  170. {
  171. LOGMESSAGE("Bind Socket Fail!");
  172. closesocket(sockListen);
  173. return -1;
  174. }
  175. nRet=listen(sockListen,5);                                   //开始监听,并设置监听客户端数量
  176. if(nRet==SOCKET_ERROR)     
  177. {
  178. LOGMESSAGE("Listening Fail!");
  179. return -1;
  180. }
  181. StartupAcceptThread();
  182. StartupWorkThread();
  183. bOverlapped = TRUE;
  184. return 0;
  185. }
  186. int CServerSocket::StopListening()
  187. {
  188. bOverlapped = FALSE;
  189. return 0;
  190. }
  191. // 返回一个空闲的SOCKET,
  192. int CServerSocket::GetEmptySocket()
  193. {
  194. for(int i=0;i<WSA_MAXIMUM_WAIT_EVENTS;i++)
  195. {
  196. if(sockAcceptArray[i]==INVALID_SOCKET)
  197. {
  198. return i;
  199. }
  200. }
  201. return -1;
  202. }
  203. bool   CServerSocket::StartupAcceptThread()
  204. {
  205. HANDLE  hAcceptThread;
  206. DWORD  dwThreadId;
  207. hAcceptThread = (HANDLE)_beginthreadex(NULL,0,(PBEGINTHREADEX_THREADFUNC)ServerListenThread,
  208. (LPVOID)this,0,(PBEGINTHREADEX_THREADID)&dwThreadId);
  209. if(hAcceptThread==NULL)
  210. {
  211. return false;
  212. }
  213. else
  214. {
  215. m_hAcceptThread=hAcceptThread;
  216. return  true;
  217. }
  218. }
  219. bool   CServerSocket::StartupWorkThread()
  220. {
  221. HANDLE hThread;
  222.         DWORD  dwThreadId;
  223.         //启动服务器工作线程
  224. hThread = (HANDLE)_beginthreadex(NULL,0,(PBEGINTHREADEX_THREADFUNC)OverlappedThread,
  225. (LPVOID)this,0,(PBEGINTHREADEX_THREADID)&dwThreadId);
  226.         if(hThread==NULL)
  227. {
  228. return false;
  229. }
  230. else
  231. m_hWorkThread=hThread;
  232.     return  true;
  233. }