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

游戏

开发平台:

Visual C++

  1. #include <stdio.h>
  2. #include <winsock2.h>
  3. #include <stdlib.h>
  4. #pragma comment (lib,"WS2_32.lib")
  5. #define SERV_TCP_PORT 9999
  6. #define DATA_BUFSIZE 1024
  7. struct _OVERLAPPELUS
  8. {
  9.     SOCKET      socket;                    
  10.     char        InBuffer[DATA_BUFSIZE];   // 输入
  11.     OVERLAPPED  ovIn;         
  12.     int         nOutBufIndex;       
  13.     char        OutBuffer[DATA_BUFSIZE];  // 输出
  14.     OVERLAPPED  ovOut;
  15.     DWORD       dwWritten;
  16. }OVERLAPPELUS, *LPOVERLAPPELUS;
  17. _OVERLAPPELUS pKey;
  18. HANDLE ghCompletionPort;
  19. void CreateWorkerThreads();
  20. DWORD WINAPI WorkerThread(LPVOID pvoid);
  21. void IssueRead(struct _OVERLAPPELUS *pCntx);
  22. void CheckOsVersion();
  23. void FatalError(char *s);
  24. void SendString(char *p,struct _OVERLAPPELUS *pCntx);
  25. ///////////////////////////////////////////////////////////
  26. int main(int argc, char *argv[])
  27. {
  28.     SOCKET  listener;
  29.     SOCKET  newsocket;
  30.     WSADATA WsaData;
  31.     struct  sockaddr_in serverAddress;
  32.     int     err;
  33.     CheckOsVersion();
  34.     err = WSAStartup (0x0202, &WsaData);
  35.     if (err == SOCKET_ERROR)
  36.     {
  37.         FatalError("网络初始化失败.");
  38.         return EXIT_FAILURE;
  39.     }
  40. if ((listener = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0,WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) 
  41. printf("WSASocket() failed with error %dn", WSAGetLastError()); 
  42. return EXIT_FAILURE; 
  43. }  
  44.     memset(&serverAddress, 0, sizeof(serverAddress));     
  45.     serverAddress.sin_family      = AF_INET;
  46.     serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);   
  47.     serverAddress.sin_port        = htons(SERV_TCP_PORT);  
  48.     err = bind(listener, (struct sockaddr *)&serverAddress, sizeof(serverAddress));
  49.     if (err < 0)
  50. {
  51.         FatalError("bind() 错误-请检查 TCP/IP 是否正确安装?");
  52. }
  53.     ghCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL,0,0);
  54.     if (ghCompletionPort == NULL)
  55. {
  56.         FatalError("CreateIoCompletionPort() 错误-请检查系统是否是Windows NT version 3.51 或更高版本.");
  57. }
  58.     CreateWorkerThreads();
  59.     listen(listener, 5);
  60.     fprintf(stderr, "I/O Completion Ports 模式:端口 %dn", SERV_TCP_PORT);
  61.     fprintf(stderr, "Ctrl+C 停止服务器程序n");
  62. printf("written by http://www.wantsoft.comn");
  63. fprintf(stderr, "开始监听客户端:n");
  64.     // 无限循环,接受并处理新的连接
  65.     while (true)
  66.     {
  67. if ((newsocket = WSAAccept(listener, NULL, NULL, NULL, 0)) == SOCKET_ERROR) 
  68. printf("WSAAccept() failed with error %dn", WSAGetLastError()); 
  69. return EXIT_FAILURE; 
  70. //建立一个 key 并初始化它.
  71. pKey.socket = newsocket;
  72.         pKey.ovOut.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //为写信息包过程设置(事件对象) event .
  73.         pKey.ovOut.hEvent = (HANDLE)((DWORD)pKey.ovOut.hEvent | 0x1); 
  74.         CreateIoCompletionPort(       //为请求绑定端口
  75. (HANDLE)newsocket,
  76. ghCompletionPort,
  77. (DWORD)&pKey,   
  78. 0 );
  79.         IssueRead(&pKey);   // 完成第一次读操作
  80.     }
  81.     return 0;
  82. }
  83. void CreateWorkerThreads()
  84. {
  85.     SYSTEM_INFO  sysinfo;
  86.     DWORD        dwThreadId;
  87.     DWORD        dwThreads;
  88.     DWORD        i;
  89.     GetSystemInfo(&sysinfo);
  90.     dwThreads = sysinfo.dwNumberOfProcessors * 2 + 2;
  91.     for (i=0; i<dwThreads; i++)
  92.     {
  93.         HANDLE hThread;
  94.         hThread = CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId);
  95.         CloseHandle(hThread);
  96.     }
  97. }
  98. // 每一个工作线程从这里开始.
  99. DWORD WINAPI WorkerThread(LPVOID pVoid)
  100. {
  101.     BOOL    bResult;
  102.     DWORD   dwNumRead;
  103.     struct _OVERLAPPELUS *pCntx;
  104.     LPOVERLAPPED lpOverlapped = NULL;
  105.     UNREFERENCED_PARAMETER(pVoid);
  106.     // 无限循环从 I/O completion port 获取信息.
  107.     while (true)
  108.     {
  109.         bResult = GetQueuedCompletionStatus(ghCompletionPort, &dwNumRead, (DWORD*)&pCntx, &lpOverlapped, INFINITE);
  110.         if (bResult == FALSE && lpOverlapped == NULL)
  111.         {
  112.             FatalError("WorkerThread - GetQueuedCompletionStatus()错误.n");
  113.         }
  114.         else if (bResult == FALSE && lpOverlapped != NULL)
  115.         {
  116. fprintf(stderr,"用户非正常退出.n"); 
  117.         }
  118.         else if (dwNumRead == 0)
  119.         {    
  120. fprintf(stderr, "用户已经退出.n");
  121.             fprintf(stderr, "------------------.n");
  122.         }
  123.         else
  124.         {
  125. printf("recv data from client: %sn", pCntx->InBuffer);
  126. SendString(pCntx->InBuffer, pCntx);
  127.             IssueRead(pCntx);
  128.         }
  129.     }
  130. ExitThread(0);
  131.     return 0;
  132. }
  133. ///////////////////////////////////////////////////////
  134. //调用 WSARecv 开始一个异步请求重复获取我们的句柄状态//
  135. ///////////////////////////////////////////////////////
  136. void IssueRead(struct _OVERLAPPELUS *pCntx)
  137. {
  138. DWORD RecvBytes;
  139. DWORD Flags =0;
  140. WSABUF DataBuff; 
  141. if (pCntx == NULL)
  142. return;
  143. memset(pCntx->InBuffer, 0, sizeof(pCntx->InBuffer));
  144.     ZeroMemory( &(pCntx->ovIn), sizeof(OVERLAPPED));
  145. DataBuff.len = DATA_BUFSIZE; 
  146. DataBuff.buf = pCntx->InBuffer; 
  147. if (WSARecv(pCntx->socket, &DataBuff, 1, &RecvBytes, &Flags, 
  148. &(pCntx->ovIn), NULL) == SOCKET_ERROR) 
  149. if (WSAGetLastError() != ERROR_IO_PENDING) 
  150. printf("WSARecv() failed with error %dn", WSAGetLastError()); 
  151. return ; 
  152. }       
  153. }
  154. // 确保我们运行在正确的版本下 Windows NT (3.51, 4.0, or later)
  155. void CheckOsVersion()
  156. {
  157.     OSVERSIONINFO   ver;
  158.     BOOL            bResult;
  159.     ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  160.     bResult = GetVersionEx((LPOSVERSIONINFO) &ver);
  161.     if ( (!bResult) ||
  162.          (ver.dwPlatformId != VER_PLATFORM_WIN32_NT) )
  163.     {
  164.         FatalError("ECHOSRV requires Windows NT 3.51 or later.");
  165.     }
  166. }
  167. //发送字符串子程序
  168. void SendString(char *p, struct _OVERLAPPELUS *pCntx)
  169. {          
  170. DWORD SendBytes;
  171. WSABUF DataBuff;
  172. int len;   
  173. strcpy(pCntx->OutBuffer,p);           
  174. len = strlen(pCntx->OutBuffer);
  175. pCntx->OutBuffer[len] = '';           
  176. pCntx->nOutBufIndex = strlen(pCntx->OutBuffer);
  177. DataBuff.len = len;
  178. DataBuff.buf = pCntx->OutBuffer;
  179. if (WSASend(pCntx->socket, &DataBuff, 1, &SendBytes, 0, 
  180. &(pCntx->ovOut), NULL) == SOCKET_ERROR) 
  181. if (WSAGetLastError() != ERROR_IO_PENDING) 
  182. printf("WSASend() failed with error %dn", WSAGetLastError()); 
  183. return ; 
  184. }
  185. // 错误句柄
  186. void FatalError(char *s)
  187. {
  188.     fprintf(stdout, "%sn", s);
  189.     exit(EXIT_FAILURE);
  190. }