将服务端select设置为非阻塞,处理更多业务
服务端代码:
- #include<WinSock2.h>
- #include<Windows.h>
- #include<vector>
- #include<stdio.h>
- #include<iostream>
- #pragma comment(lib,"ws2_32.lib")
- enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_ERROR };
- //包头
- struct DataHeader
- {
- short dataLength;
- short cmd;
- };
- //包体
- struct Login:public DataHeader
- {
- Login()
- {
- dataLength = sizeof(Login);
- cmd = CMD_Login;
- }
- char username[];
- char password[];
- };
- struct LoginResult :public DataHeader
- {
- LoginResult()
- {
- dataLength = sizeof(LoginResult);
- cmd = CMD_Login_Result;
- result = ;
- }
- int result;
- };
- struct Logout :public DataHeader
- {
- Logout()
- {
- dataLength = sizeof(Logout);
- cmd = CMD_Logout;
- }
- char username[];
- };
- struct LogoutResult :public DataHeader
- {
- LogoutResult()
- {
- dataLength = sizeof(LogoutResult);
- cmd = CMD_Logout_Result;
- result = ;
- }
- int result;
- };
- std::vector<SOCKET> g_client;
- int process_solve(SOCKET _cSOCK)
- {
- //增加一个缓冲区
- char szRecv[] = {};
- //5.接收客户端新数据
- int nLen = recv(_cSOCK, szRecv, sizeof(DataHeader), );
- DataHeader *header = (DataHeader*)szRecv;
- if (nLen <= )
- {
- printf("客户端已退出!任务结束!");
- return -;
- }
- switch (header->cmd){
- case CMD_Login:
- {
- recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), );
- Login *login = (Login*)szRecv;
- printf("收到命令:CMD_Login,数据长度:%d\nUserName:%s\nPassWord:%s\n", login->dataLength, login->username, login->password);
- //忽略判断用户密码是否正确的过程
- LoginResult ret;
- send(_cSOCK, (char *)&ret, sizeof(LoginResult), ); //再发消息体
- }
- case CMD_Logout:
- {
- recv(_cSOCK, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), );
- Logout* logout = (Logout*)szRecv;
- printf("收到命令:CMD_Logout,数据长度:%d\nUserName:%s\n", logout->dataLength, logout->username);
- //忽略判断用户密码是否正确的过程
- LogoutResult let;
- send(_cSOCK, (char *)&let, sizeof(let), ); //再发消息体
- }
- break;
- default:
- {
- DataHeader header = { };
- send(_cSOCK, (char *)&header.cmd, sizeof(header), );
- }
- break;
- }
- }
- int main()
- {
- WORD ver = MAKEWORD(, );
- WSADATA dat;
- //WinSocket启动
- WSAStartup(ver, &dat);
- //1、建立一个socket
- SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); //AF_INET创建一个IPV4的套接字,SOCK_STREAM面向数据流的,IPPROTO_TCP TCP
- if (INVALID_SOCKET == _sock)
- {
- printf("ERROR:建立失败!\n");
- }
- //2.绑定
- sockaddr_in _sin = {}; //创建网络地址
- _sin.sin_family = AF_INET;
- _sin.sin_port = htons(); //Host to Network Short
- _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); // IP地址
- if (bind(_sock, (sockaddr *)&_sin, sizeof(_sin)) == SOCKET_ERROR)
- {
- printf("ERROR:绑定失败!\n");
- }
- else
- {
- printf("服务器端绑定成功......\n");
- }
- //3.监听网络端口
- if (listen(_sock, ) == SOCKET_ERROR)//第二个参数为最大等待多少人可以同时连接
- {
- printf("ERROR:监听失败!\n");
- }
- else
- {
- printf("服务器端监听成功......\n");
- }
- while ()
- {
- //伯克利 socket
- fd_set fd_Read;
- fd_set fd_Write;
- fd_set fd_Exp;
- FD_ZERO(&fd_Read);//FD_ZERO 清空集合里的数据
- FD_ZERO(&fd_Write);
- FD_ZERO(&fd_Exp);
- FD_SET(_sock, &fd_Read);//FD_SET 可以进行操作的宏
- FD_SET(_sock, &fd_Write);
- FD_SET(_sock, &fd_Exp);
- for (int n = g_client.size() - ; n >= ; n--)
- {
- FD_SET(g_client[n], &fd_Read);
- }
- /*
- select(
- _In_ int nfds,
- _Inout_opt_ fd_set FAR * readfds,
- _Inout_opt_ fd_set FAR * writefds,
- _Inout_opt_ fd_set FAR * exceptfds,
- _In_opt_ const struct timeval FAR * timeout
- );
- */
- //nfds是一个整数值,是指fd_set集合所有的描述符(select里的第一个参数)的范围(而不是数量)
- //既是所有文件描述符最大值+1
- timeval t = {,};
- int ret = select(_sock + , &fd_Read, &fd_Write, &fd_Exp, &t);
- if (ret < )
- {
- printf("select任务结束!\n");
- break;
- }
- if (FD_ISSET(_sock, &fd_Read))
- {
- FD_CLR(_sock, &fd_Read);
- //4.等待接收客户端连接
- sockaddr_in clientAddr = {};
- int nAddrLen = sizeof(sockaddr_in);
- SOCKET _cSOCK = INVALID_SOCKET;
- _cSOCK = accept(_sock, (sockaddr *)&clientAddr, &nAddrLen);
- if (_cSOCK == INVALID_SOCKET)
- {
- printf("ERROR:无效客户端SOCKET!\n");
- }
- g_client.push_back(_cSOCK);
- printf("新客户端加入:Socket=%d,IP = %s\n", (int)_cSOCK, inet_ntoa(clientAddr.sin_addr));//inet_ntoa(clientAddr.sin_addr)将接收到的IP地址转化为字符串
- }
- for (int n = ; n < fd_Read.fd_count; n++)
- {
- if (process_solve(fd_Read.fd_array[n]) == -)
- {
- auto iter = find(g_client.begin(), g_client.end(), process_solve(fd_Read.fd_array[n]));
- if (iter != g_client.end())
- {
- g_client.erase(iter);
- }
- }
- }
- }
- for (int n = g_client.size(); n >= ; n--)
- {
- //8.关闭自身的socket
- closesocket(g_client[n]);
- }
- //8.关闭自身的socket
- closesocket(_sock);
- //WinSocket关闭
- WSACleanup();
- system("pause");
- return ;
- }
客户端代码:
- #include<WinSock2.h>
- #include<Windows.h>
- #include<stdio.h>
- #pragma comment(lib,"ws2_32.lib")
- enum CMD { CMD_Login, CMD_Login_Result, CMD_Logout, CMD_Logout_Result, CMD_ERROR };
- //包头
- struct DataHeader
- {
- short dataLength;
- short cmd;
- };
- //包体
- struct Login :public DataHeader
- {
- Login()
- {
- dataLength = sizeof(Login);
- cmd = CMD_Login;
- }
- char username[];
- char password[];
- };
- struct LoginResult :public DataHeader
- {
- LoginResult()
- {
- dataLength = sizeof(LoginResult);
- cmd = CMD_Login_Result;
- result = ;
- }
- int result;
- };
- struct Logout :public DataHeader
- {
- Logout()
- {
- dataLength = sizeof(Logout);
- cmd = CMD_Logout;
- }
- char username[];
- };
- struct LogoutResult :public DataHeader
- {
- LogoutResult()
- {
- dataLength = sizeof(LogoutResult);
- cmd = CMD_Logout_Result;
- result = ;
- }
- int result;
- };
- int main()
- {
- WORD ver = MAKEWORD(, );
- WSADATA dat;
- WSAStartup(ver, &dat);
- //1.建立一个socket
- SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (INVALID_SOCKET == _sock)
- {
- printf("ERROR:建立失败!\n");
- }
- else{
- printf("客户端绑定成功......\n");
- }
- //2.连接服务器
- sockaddr_in _sin = {}; //创建网络地址
- _sin.sin_family = AF_INET;
- _sin.sin_port = htons(); //Host to Network Short
- _sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//inet_addr("127.0.0.1"); // IP地址
- int ret = connect(_sock, (sockaddr *)&_sin, sizeof(sockaddr_in));
- if (SOCKET_ERROR == ret)
- {
- printf("ERROR:连接失败!\n");
- }
- else
- {
- printf("客户端连接成功......\n");
- }
- while (true)
- {
- //3.输入请求命令
- char cmdBuff[] = {};
- scanf("%s", cmdBuff);
- //4.处理请求命令
- if ( == strcmp(cmdBuff, "exit"))
- {
- printf("收到exit命令,已退出!");
- break;
- }
- else if ( == strcmp(cmdBuff, "login")){
- Login login;
- strcpy(login.username, "sutaoyu01");
- strcpy(login.password, "sutaoyu01");
- //5.向服务器发送请求命令
- send(_sock, (const char*)&login, sizeof(login), );
- //接收服务器返回的数据
- LoginResult resulrtRet = {};
- recv(_sock, (char*)&resulrtRet, sizeof(resulrtRet), );
- printf("LoginResult:%d\n", resulrtRet.result);
- }
- else if ( == strcmp(cmdBuff, "logout")){
- Logout logout;
- strcpy(logout.username, "sutaoyu01");
- //5.向服务器发送请求命令
- send(_sock, (const char*)&logout, sizeof(logout), );
- //接收服务器返回的数据
- LogoutResult resultRet = {};
- recv(_sock, (char*)&resultRet, sizeof(resultRet), );
- printf("LogoutResult:%d\n", resultRet.result);
- }
- else{
- printf("不支持的命令,请重新输入!");
- }
- }
- //7.关闭套接字
- closesocket(_sock);
- //WinSocket启动
- WSAStartup(ver, &dat);
- //WinSocket关闭
- WSACleanup();
- printf("已退出!");
- getchar();
- return ;
- }
将服务端select设置为非阻塞,处理更多业务的更多相关文章
- socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto
socket异步通信-如何设置成非阻塞模式.非阻塞模式下判断connect成功(失败).判断recv/recvfrom成功(失败).判断send/sendto 博客分类: Linux Socket s ...
- socket设置为非阻塞方式(windows和linux)
Windows用以下方法将socket设置为非阻塞方式 : unsigned long ul=1; SOCKET s=socket(AF_INET,SOCK_STREAM,0); int ret=io ...
- 单点登录(SSO)解决方案之 CAS服务端数据源设置及页面改造
接上篇 单点登录(SSO)解决方案之 CAS 入门案例 服务端数据源设置: 开发中,我们登录的user信息都是存在数据库中的,下面说一下如何让用户名密码从我们的数据库表中做验证. 案例中我最终把cas ...
- CAS服务端数据源设置
2.CAS服务端数据源设置 2.1需求分析 我们现在让用户名密码从我们的品优购的user表里做验证 2.2配置数据源 (1)修改cas服务端中web-inf下deployerConfigContext ...
- 服务器编程心得(四)—— 如何将socket设置为非阻塞模式
1. windows平台上无论利用socket()函数还是WSASocket()函数创建的socket都是阻塞模式的: SOCKET WSAAPI socket( _In_ int af, _In_ ...
- 防止网页被别人的网站iframe,服务端如何设置HTTP头部中的X-Frame-Options信息?
一.现象:in a frame because it set 'X-Frame-Options' to 'deny'. 二.服务配置 因为,有时候为了防止网页被别人的网站iframe,我们可以通过在服 ...
- 练习C之SELECT形式的非阻塞IO
呵呵,理解得不深,但毕竟手打全版,且无错.但select.h不知何处找头文件, 粘下来作个记录. POLL,EPOLL感觉代码类似,只是函数和系统实现不一样,,EPOLL目前最合理的.定位精确,算法复 ...
- aiohttp web服务端(server)样例 (非client)
python版本 python3.6 (其他版本需要小改,版本>python3.4) 参考网址:https://www.cnblogs.com/ameile/p/5589808.html as ...
- Crontab在服务端进行设置定时执行任务
Crontab简crontab是一个可以根据时间.日期.月份.星期的组合调度对重复任务的执行的守护进程.也可以讲Linux crontab是用来定期执行程序的命令. 当安装完成操作系统之后,默认便会启 ...
随机推荐
- unity读取灰度图生成等值线图
准备灰度图 grayTest.png,放置于Assets下StreamingAssets文件夹中. 在场景中添加RawImage用于显示最后的等值线图. 生成等值线的过程,使用Marching ...
- Python3 Selenium自动化web测试 ==> 第一节 起始点之Python单元测试框架 unittest
前置步骤 Python版本:3.6.4 selenium版本:3.11.0 >>> import selenium >>> help(selenium) IDE:P ...
- CG标准函数
- 如何快速在Github找到你想要的东西
众所周知 Github是全球最大的xx交友平台,虽然被收购了.但是不并没有什么影响. 使用Git可以做很多事,在这里不再缀述,上面的资源也是多种多样,应有尽有 对于这样一个平台,我们想快速找到自己需要 ...
- Java学习笔记-抽象类与接口
抽象类用于在类中不用具体实现,而在子类中去实现的类 抽象类 抽象类概述 抽象定义:抽象就是从多个事物中将共性的,本质的内容抽取出来 抽象类:Java中可以定义没有方法体的方法,该方法的具体实现由子类完 ...
- js 数组遍历 对象遍历
一.数组遍历 1,普通for循环,经常用的数组遍历 var arr = [1,2,0,3,9]; for ( var i = 0; i <arr.length; i++){ console.lo ...
- SQL查询表的第一条数据和最后一条数据
方法一: 使用TOP SELECT TOP 1 * FROM user; SELECT TOP 1 * FROM user order by id desc; 方法二: 使用LIMIT SELECT ...
- list集合的一些小见解
关于LIst集合 前言: 第一次写博客,有些东西可能总结的到位,发表一下自己的一些观点,欢迎大佬们点评和指教 正文: list集合可以分为ArrayLlst和LinkedList. ArrayList ...
- linux基础命令笔记
配置IP地址 vi /etc/sysconfig/network-scripts/ifcfg-eth0 忘记root密码grub e 选择kernel按e 输入single b 1:目录及文件的基本操 ...
- hanlp自然语言处理包的人名识别代码解析
HanLP发射矩阵词典nr.txt中收录单字姓氏393个.袁义达在<中国的三大姓氏是如何统计出来的>文献中指出:当代中国100个常见姓氏中,集中了全国人口的87%,根据这一数据我们只保留n ...