服务端代码:

  1. #include<WinSock2.h>
  2. #include<Windows.h>
  3. #include<vector>
  4. #include<stdio.h>
  5. #include<iostream>
  6.  
  7. #pragma comment(lib,"ws2_32.lib")
  8.  
  9. enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_ERROR };
  10.  
  11. //包头
  12. struct DataHeader
  13. {
  14. short dataLength;
  15. short cmd;
  16. };
  17. //包体
  18. struct Login:public DataHeader
  19. {
  20. Login()
  21. {
  22. dataLength = sizeof(Login);
  23. cmd = CMD_Login;
  24. }
  25. char username[];
  26. char password[];
  27. };
  28.  
  29. struct LoginResult :public DataHeader
  30. {
  31. LoginResult()
  32. {
  33. dataLength = sizeof(LoginResult);
  34. cmd = CMD_Login_Result;
  35. result = ;
  36. }
  37. int result;
  38. };
  39.  
  40. struct Logout :public DataHeader
  41. {
  42. Logout()
  43. {
  44. dataLength = sizeof(Logout);
  45. cmd = CMD_Logout;
  46. }
  47. char username[];
  48. };
  49.  
  50. struct LogoutResult :public DataHeader
  51. {
  52. LogoutResult()
  53. {
  54. dataLength = sizeof(LogoutResult);
  55. cmd = CMD_Logout_Result;
  56. result = ;
  57. }
  58. int result;
  59. };
  60.  
  61. std::vector<SOCKET> g_client;
  62.  
  63. int process_solve(SOCKET _cSOCK)
  64. {
  65. //增加一个缓冲区
  66. char szRecv[] = {};
  67. //5.接收客户端新数据
  68. int nLen = recv(_cSOCK, szRecv, sizeof(DataHeader), );
  69. DataHeader *header = (DataHeader*)szRecv;
  70.  
  71. if (nLen <= )
  72. {
  73. printf("客户端已退出!任务结束!");
  74. return -;
  75. }
  76. switch (header->cmd){
  77. case CMD_Login:
  78. {
  79. recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), );
  80. Login *login = (Login*)szRecv;
  81. printf("收到命令:CMD_Login,数据长度:%d\nUserName:%s\nPassWord:%s\n", login->dataLength, login->username, login->password);
  82. //忽略判断用户密码是否正确的过程
  83. LoginResult ret;
  84. send(_cSOCK, (char *)&ret, sizeof(LoginResult), ); //再发消息体
  85.  
  86. }
  87. case CMD_Logout:
  88. {
  89.  
  90. recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), );
  91. Logout* logout = (Logout*)szRecv;
  92. printf("收到命令:CMD_Logout,数据长度:%d\nUserName:%s\n", logout->dataLength, logout->username);
  93.  
  94. //忽略判断用户密码是否正确的过程
  95. LogoutResult let;
  96. send(_cSOCK, (char *)&let, sizeof(let), ); //再发消息体
  97. }
  98. break;
  99. default:
  100. {
  101. DataHeader header = { };
  102. send(_cSOCK, (char *)&header.cmd, sizeof(header), );
  103. }
  104.  
  105. break;
  106. }
  107. }
  108.  
  109. int main()
  110. {
  111.  
  112. WORD ver = MAKEWORD(, );
  113. WSADATA dat;
  114. //WinSocket启动
  115. WSAStartup(ver, &dat);
  116.  
  117. //1、建立一个socket
  118. SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //AF_INET创建一个IPV4的套接字,SOCK_STREAM面向数据流的,IPPROTO_TCP TCP
  119. if (INVALID_SOCKET == _sock)
  120. {
  121. printf("ERROR:建立失败!\n");
  122. }
  123. //2.绑定
  124. sockaddr_in _sin = {}; //创建网络地址
  125. _sin.sin_family = AF_INET;
  126. _sin.sin_port = htons(); //Host to Network Short
  127. _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // IP地址
  128. if (bind(_sock, (sockaddr *)&_sin, sizeof(_sin)) == SOCKET_ERROR)
  129. {
  130. printf("ERROR:绑定失败!\n");
  131. }
  132. else
  133. {
  134. printf("服务器端绑定成功......\n");
  135. }
  136. //3.监听网络端口
  137. if (listen(_sock, ) == SOCKET_ERROR)//第二个参数为最大等待多少人可以同时连接
  138. {
  139. printf("ERROR:监听失败!\n");
  140. }
  141. else
  142. {
  143. printf("服务器端监听成功......\n");
  144. }
  145.  
  146. while ()
  147. {
  148. //伯克利 socket
  149. fd_set fd_Read;
  150. fd_set fd_Write;
  151. fd_set fd_Exp;
  152.  
  153. FD_ZERO(&fd_Read);//FD_ZERO 清空集合里的数据
  154. FD_ZERO(&fd_Write);
  155. FD_ZERO(&fd_Exp);
  156.  
  157. FD_SET(_sock, &fd_Read);//FD_SET 可以进行操作的宏
  158. FD_SET(_sock, &fd_Write);
  159. FD_SET(_sock, &fd_Exp);
  160.  
  161. for (int n = g_client.size() - ; n >= ; n--)
  162. {
  163. FD_SET(g_client[n], &fd_Read);
  164. }
  165.  
  166. /*
  167. select(
  168. _In_ int nfds,
  169. _Inout_opt_ fd_set FAR * readfds,
  170. _Inout_opt_ fd_set FAR * writefds,
  171. _Inout_opt_ fd_set FAR * exceptfds,
  172. _In_opt_ const struct timeval FAR * timeout
  173. );
  174. */
  175.  
  176. //nfds是一个整数值,是指fd_set集合所有的描述符(select里的第一个参数)的范围(而不是数量)
  177. //既是所有文件描述符最大值+1
  178. timeval t = {,};
  179.  
  180. int ret = select(_sock + , &fd_Read, &fd_Write, &fd_Exp, &t);
  181. if (ret < )
  182. {
  183. printf("select任务结束!\n");
  184. break;
  185. }
  186. if (FD_ISSET(_sock, &fd_Read))
  187. {
  188. FD_CLR(_sock, &fd_Read);
  189. //4.等待接收客户端连接
  190. sockaddr_in clientAddr = {};
  191. int nAddrLen = sizeof(sockaddr_in);
  192. SOCKET _cSOCK = INVALID_SOCKET;
  193.  
  194. _cSOCK = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen);
  195. if (_cSOCK == INVALID_SOCKET)
  196. {
  197. printf("ERROR:无效客户端SOCKET!\n");
  198. }
  199. g_client.push_back(_cSOCK);
  200. printf("新客户端加入:Socket=%d,IP = %s\n", (int)_cSOCK, inet_ntoa(clientAddr.sin_addr));//inet_ntoa(clientAddr.sin_addr)将接收到的IP地址转化为字符串
  201.  
  202. }
  203.  
  204. for (int n = ; n < fd_Read.fd_count; n++)
  205. {
  206. if (process_solve(fd_Read.fd_array[n]) == -)
  207. {
  208. auto iter = find(g_client.begin(), g_client.end(), process_solve(fd_Read.fd_array[n]));
  209. if (iter != g_client.end())
  210. {
  211. g_client.erase(iter);
  212. }
  213. }
  214. }
  215. }
  216.  
  217. for (int n = g_client.size(); n >= ; n--)
  218. {
  219. //8.关闭自身的socket
  220. closesocket(g_client[n]);
  221. }
  222.  
  223. //8.关闭自身的socket
  224. closesocket(_sock);
  225.  
  226. //WinSocket关闭
  227. WSACleanup();
  228.  
  229. system("pause");
  230. return ;
  231. }

客户端代码:

  1. #include<WinSock2.h>
  2. #include<Windows.h>
  3. #include<stdio.h>
  4.  
  5. #pragma comment(lib,"ws2_32.lib")
  6.  
  7. enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_ERROR };
  8.  
  9. //包头
  10. struct DataHeader
  11. {
  12. short dataLength;
  13. short cmd;
  14. };
  15. //包体
  16. struct Login :public DataHeader
  17. {
  18. Login()
  19. {
  20. dataLength = sizeof(Login);
  21. cmd = CMD_Login;
  22. }
  23. char username[];
  24. char password[];
  25. };
  26.  
  27. struct LoginResult :public DataHeader
  28. {
  29. LoginResult()
  30. {
  31. dataLength = sizeof(LoginResult);
  32. cmd = CMD_Login_Result;
  33. result = ;
  34. }
  35. int result;
  36. };
  37.  
  38. struct Logout :public DataHeader
  39. {
  40. Logout()
  41. {
  42. dataLength = sizeof(Logout);
  43. cmd = CMD_Logout;
  44. }
  45. char username[];
  46. };
  47.  
  48. struct LogoutResult :public DataHeader
  49. {
  50. LogoutResult()
  51. {
  52. dataLength = sizeof(LogoutResult);
  53. cmd = CMD_Logout_Result;
  54. result = ;
  55. }
  56. int result;
  57. };
  58.  
  59. int main()
  60. {
  61. WORD ver = MAKEWORD(, );
  62. WSADATA dat;
  63. WSAStartup(ver, &dat);
  64.  
  65. //1.建立一个socket
  66. SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  67. if (INVALID_SOCKET == _sock)
  68. {
  69. printf("ERROR:建立失败!\n");
  70. }
  71. else{
  72. printf("客户端绑定成功......\n");
  73. }
  74. //2.连接服务器
  75. sockaddr_in _sin = {}; //创建网络地址
  76. _sin.sin_family = AF_INET;
  77. _sin.sin_port = htons(); //Host to Network Short
  78. _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//inet_addr("127.0.0.1"); // IP地址
  79. int ret = connect(_sock, (sockaddr *)&_sin, sizeof(sockaddr_in));
  80. if (SOCKET_ERROR == ret)
  81. {
  82. printf("ERROR:连接失败!\n");
  83. }
  84. else
  85. {
  86. printf("客户端连接成功......\n");
  87. }
  88.  
  89. while (true)
  90. {
  91. //3.输入请求命令
  92. char cmdBuff[] = {};
  93. scanf("%s", cmdBuff);
  94. //4.处理请求命令
  95. if ( == strcmp(cmdBuff, "exit"))
  96. {
  97. printf("收到exit命令,已退出!");
  98. break;
  99. }
  100. else if ( == strcmp(cmdBuff, "login")){
  101. Login login;
  102. strcpy(login.username, "sutaoyu01");
  103. strcpy(login.password, "sutaoyu01");
  104.  
  105. //5.向服务器发送请求命令
  106. send(_sock, (const char*)&login, sizeof(login), );
  107.  
  108. //接收服务器返回的数据
  109. LoginResult resulrtRet = {};
  110. recv(_sock, (char*)&resulrtRet, sizeof(resulrtRet), );
  111. printf("LoginResult:%d\n", resulrtRet.result);
  112. }
  113. else if ( == strcmp(cmdBuff, "logout")){
  114. Logout logout;
  115. strcpy(logout.username, "sutaoyu01");
  116. //5.向服务器发送请求命令
  117. send(_sock, (const char*)&logout, sizeof(logout), );
  118. //接收服务器返回的数据
  119. LogoutResult resultRet = {};
  120. recv(_sock, (char*)&resultRet, sizeof(resultRet), );
  121. printf("LogoutResult:%d\n", resultRet.result);
  122. }
  123. else{
  124. printf("不支持的命令,请重新输入!");
  125. }
  126. }
  127.  
  128. //7.关闭套接字
  129. closesocket(_sock);
  130.  
  131. //WinSocket启动
  132. WSAStartup(ver, &dat);
  133.  
  134. //WinSocket关闭
  135. WSACleanup();
  136. printf("已退出!");
  137. getchar();
  138. return ;
  139. }

将服务端select设置为非阻塞,处理更多业务的更多相关文章

  1. socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto

    socket异步通信-如何设置成非阻塞模式.非阻塞模式下判断connect成功(失败).判断recv/recvfrom成功(失败).判断send/sendto 博客分类: Linux Socket s ...

  2. socket设置为非阻塞方式(windows和linux)

    Windows用以下方法将socket设置为非阻塞方式 : unsigned long ul=1; SOCKET s=socket(AF_INET,SOCK_STREAM,0); int ret=io ...

  3. 单点登录(SSO)解决方案之 CAS服务端数据源设置及页面改造

    接上篇 单点登录(SSO)解决方案之 CAS 入门案例 服务端数据源设置: 开发中,我们登录的user信息都是存在数据库中的,下面说一下如何让用户名密码从我们的数据库表中做验证. 案例中我最终把cas ...

  4. CAS服务端数据源设置

    2.CAS服务端数据源设置 2.1需求分析 我们现在让用户名密码从我们的品优购的user表里做验证 2.2配置数据源 (1)修改cas服务端中web-inf下deployerConfigContext ...

  5. 服务器编程心得(四)—— 如何将socket设置为非阻塞模式

    1. windows平台上无论利用socket()函数还是WSASocket()函数创建的socket都是阻塞模式的: SOCKET WSAAPI socket( _In_ int af, _In_ ...

  6. 防止网页被别人的网站iframe,服务端如何设置HTTP头部中的X-Frame-Options信息?

    一.现象:in a frame because it set 'X-Frame-Options' to 'deny'. 二.服务配置 因为,有时候为了防止网页被别人的网站iframe,我们可以通过在服 ...

  7. 练习C之SELECT形式的非阻塞IO

    呵呵,理解得不深,但毕竟手打全版,且无错.但select.h不知何处找头文件, 粘下来作个记录. POLL,EPOLL感觉代码类似,只是函数和系统实现不一样,,EPOLL目前最合理的.定位精确,算法复 ...

  8. aiohttp web服务端(server)样例 (非client)

    python版本 python3.6 (其他版本需要小改,版本>python3.4) 参考网址:https://www.cnblogs.com/ameile/p/5589808.html  as ...

  9. Crontab在服务端进行设置定时执行任务

    Crontab简crontab是一个可以根据时间.日期.月份.星期的组合调度对重复任务的执行的守护进程.也可以讲Linux crontab是用来定期执行程序的命令. 当安装完成操作系统之后,默认便会启 ...

随机推荐

  1. unity读取灰度图生成等值线图

    准备灰度图 grayTest.png,放置于Assets下StreamingAssets文件夹中.   在场景中添加RawImage用于显示最后的等值线图.   生成等值线的过程,使用Marching ...

  2. Python3 Selenium自动化web测试 ==> 第一节 起始点之Python单元测试框架 unittest

    前置步骤 Python版本:3.6.4 selenium版本:3.11.0 >>> import selenium >>> help(selenium) IDE:P ...

  3. CG标准函数

  4. 如何快速在Github找到你想要的东西

    众所周知 Github是全球最大的xx交友平台,虽然被收购了.但是不并没有什么影响. 使用Git可以做很多事,在这里不再缀述,上面的资源也是多种多样,应有尽有 对于这样一个平台,我们想快速找到自己需要 ...

  5. Java学习笔记-抽象类与接口

    抽象类用于在类中不用具体实现,而在子类中去实现的类 抽象类 抽象类概述 抽象定义:抽象就是从多个事物中将共性的,本质的内容抽取出来 抽象类:Java中可以定义没有方法体的方法,该方法的具体实现由子类完 ...

  6. js 数组遍历 对象遍历

    一.数组遍历 1,普通for循环,经常用的数组遍历 var arr = [1,2,0,3,9]; for ( var i = 0; i <arr.length; i++){ console.lo ...

  7. SQL查询表的第一条数据和最后一条数据

    方法一: 使用TOP SELECT TOP 1 * FROM user; SELECT TOP 1 * FROM user order by id desc; 方法二: 使用LIMIT SELECT  ...

  8. list集合的一些小见解

    关于LIst集合 前言: 第一次写博客,有些东西可能总结的到位,发表一下自己的一些观点,欢迎大佬们点评和指教 正文: list集合可以分为ArrayLlst和LinkedList. ArrayList ...

  9. linux基础命令笔记

    配置IP地址 vi /etc/sysconfig/network-scripts/ifcfg-eth0 忘记root密码grub e 选择kernel按e 输入single b 1:目录及文件的基本操 ...

  10. hanlp自然语言处理包的人名识别代码解析

    HanLP发射矩阵词典nr.txt中收录单字姓氏393个.袁义达在<中国的三大姓氏是如何统计出来的>文献中指出:当代中国100个常见姓氏中,集中了全国人口的87%,根据这一数据我们只保留n ...