文章目录

  • 1 服务端升级为select模型处理多客户端
    • 1.1 概述
    • 1.2 服务端实现

1 服务端升级为select模型处理多客户端

1.1 概述

之前我们的设计是服务端与客户端1对1的阻塞模式网络程序,我们这里对服务端进行升级,引入select模型,使得服务端有能力处理多个客户端。


Socket的select模型:

int select (int nfds,                           fd_set FAR * readfds,               fd_set FAR * writefds,              fd_set FAR * exceptfds,             const struct timeval FAR * timeout
);

1.2 服务端实现

server.cpp:

#define WIN32_LEAN_AND_MEAN
#define _WINSOCK_DEPRECATED_NO_WARNINGS#include<windows.h>
#include<WinSock2.h>
#include<stdio.h>#include <vector>#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;
};//DataPackage
struct Login: public DataHeader
{Login(){dataLength = sizeof(Login);cmd = CMD_LOGIN;}char userName[32];char PassWord[32];
};struct LoginResult : public DataHeader
{LoginResult(){dataLength = sizeof(LoginResult);cmd = CMD_LOGIN_RESULT;result = 0;}int result;
};struct Logout : public DataHeader
{Logout(){dataLength = sizeof(Logout);cmd = CMD_LOGOUT;}char userName[32];
};struct LogoutResult : public DataHeader
{LogoutResult(){dataLength = sizeof(LogoutResult);cmd = CMD_LOGIN_RESULT;result = 0;}int result;
};std::vector<SOCKET> g_clients;int processor(SOCKET _cSock)
{//缓冲区char szRecv[4096] = {};// 5 接收客户端数据int nLen = recv(_cSock, szRecv, sizeof(DataHeader), 0);DataHeader* header = (DataHeader*)szRecv;if (nLen <= 0){printf("客户端已退出,任务结束。\n");return -1;}switch (header->cmd){case CMD_LOGIN:{recv(_cSock, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);Login* login = (Login*)szRecv;printf("收到命令:CMD_LOGIN,数据长度:%d,userName=%s PassWord=%s\n", login->dataLength, login->userName, login->PassWord);//忽略判断用户密码是否正确的过程LoginResult ret;send(_cSock, (char*)&ret, sizeof(LoginResult), 0);}break;case CMD_LOGOUT:{recv(_cSock, szRecv + sizeof(DataHeader), header->dataLength - sizeof(DataHeader), 0);Logout* logout = (Logout*)szRecv;printf("收到命令:CMD_LOGOUT,数据长度:%d,userName=%s \n", logout->dataLength, logout->userName);//忽略判断用户密码是否正确的过程LogoutResult ret;send(_cSock, (char*)&ret, sizeof(ret), 0);}break;default:{DataHeader header = { 0,CMD_ERROR };send(_cSock, (char*)&header, sizeof(header), 0);}break;}
}int main()
{//启动Windows socket 2.x环境WORD ver = MAKEWORD(2, 2);WSADATA dat;WSAStartup(ver, &dat);//------------//-- 用Socket API建立简易TCP服务端// 1 建立一个socket 套接字SOCKET _sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// 2 bind 绑定用于接受客户端连接的网络端口sockaddr_in _sin = {};_sin.sin_family = AF_INET;_sin.sin_port = htons(4567);//host to net unsigned short_sin.sin_addr.S_un.S_addr = INADDR_ANY;//inet_addr("127.0.0.1");if (SOCKET_ERROR == bind(_sock, (sockaddr*)&_sin, sizeof(_sin))){printf("错误,绑定网络端口失败...\n");}else {printf("绑定网络端口成功...\n");}// 3 listen 监听网络端口if (SOCKET_ERROR == listen(_sock, 5)){printf("错误,监听网络端口失败...\n");}else {printf("监听网络端口成功...\n");}while (true){//伯克利 socketfd_set fdRead;fd_set fdWrite;fd_set fdExp;FD_ZERO(&fdRead);FD_ZERO(&fdWrite);FD_ZERO(&fdExp);FD_SET(_sock, &fdRead);FD_SET(_sock, &fdWrite);FD_SET(_sock, &fdExp);for (int n = (int)g_clients.size()-1; n >= 0 ; n--){FD_SET(g_clients[n], &fdRead);}///nfds 是一个整数值 是指fd_set集合中所有描述符(socket)的范围,而不是数量///既是所有文件描述符最大值+1 在Windows中这个参数可以写0timeval t = {0,0};int ret = select(_sock + 1, &fdRead, &fdWrite, &fdExp, &t);if (ret < 0){printf("select任务结束。\n");break;}if (FD_ISSET(_sock, &fdRead)){FD_CLR(_sock, &fdRead);// 4 accept 等待接受客户端连接sockaddr_in clientAddr = {};int nAddrLen = sizeof(sockaddr_in);SOCKET _cSock = INVALID_SOCKET;_cSock = accept(_sock, (sockaddr*)&clientAddr, &nAddrLen);if (INVALID_SOCKET == _cSock){printf("错误,接受到无效客户端SOCKET...\n");}g_clients.push_back(_cSock);printf("新客户端加入:socket = %d,IP = %s \n", (int)_cSock, inet_ntoa(clientAddr.sin_addr));}for (size_t n = 0; n < fdRead.fd_count; n++){if (-1 == processor(fdRead.fd_array[n])){auto iter = find(g_clients.begin(), g_clients.end(), fdRead.fd_array[n]);if (iter != g_clients.end()){g_clients.erase(iter);}}}}for (size_t n = g_clients.size() - 1; n >= 0; n--){closesocket(g_clients[n]);}// 8 关闭套节字closesocketclosesocket(_sock);//------------//清除Windows socket环境WSACleanup();printf("已退出。\n");getchar();return 0;
}

参考资料:

  1. C++ 百万并发网络通信引擎架构与实现 (服务端、客户端、跨平台) Version 1.0

服务端升级为select模型处理多客户端相关推荐

  1. commvault服务端升级到2022E版本 自动安装客户端11.28版本 xtrabackup备份与恢复

    之前在官网下载的安装包,大小30.4M,安装后发现是11.24版本的 所以要继续升级 https://cloud.commvault.com/webconsole/softwarestore/stor ...

  2. 客户端升级为select模型

    文章目录 1 客户端升级为select模型 1.1 概述 1.2 客户端代码实现 1.3 服务端代码实现 1 客户端升级为select模型 1.1 概述 这里我们为了让客户端有时间去处理其它业务逻辑, ...

  3. C#开发BIMFACE系列19 服务端API之获取模型数据4:获取多个构件的共同属性

    系列目录     [已更新最新开发文章,点击查看详细] 在前几篇博客中介绍了一个三维文件/模型包含多个构建,每个构建又是由多种材质组成,每个构建都有很多属性.不同的构建也有可能包含相同的属性. 上图中 ...

  4. C#开发BIMFACE系列20 服务端API之获取模型数据5:批量获取构件属性

    系列目录     [已更新最新开发文章,点击查看详细] 在<C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性>中介绍了获取单个文件/模型的单个构建的属性,本篇介绍 ...

  5. C#开发BIMFACE系列18 服务端API之获取模型数据3:获取构件属性

    系列目录     [已更新最新开发文章,点击查看详细] 本篇主要介绍如何获取单文件/模型下单个构建的属性信息. 请求地址:GET https://api.bimface.com/data/v2/fil ...

  6. 服务端升级 Ubuntu 20.04 LTS 记录

    本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载.或重新修改使用,但需要注明来源. 署名 4.0 国际 (CC BY 4.0) 本文作者: 苏洋 创建时间: 2020年04月2 ...

  7. python实现socket编程,服务端开启多线程(和多个客户端聊天)

    首先运行服务端,待服务端运行起来之后,最后开始运行客户端进行对话,可以运行多个客户端和服务端对话,注意这个开启的客户端的顺序和服务端的聊天顺序(其实就是阻塞,待上一个客户端和服务端的一段对话结束之后, ...

  8. 原神服务端搭建架设教程win系统(附客户端+服务端+环境配置)

    原神服务端搭建架设教程win系统(附客户端+服务端+环境配置) 大家好,我是艾西原神一款开放世界冒险3D游戏以七种元素(分别为风.雷.岩.火.水.草.冰)交汇的幻想世界"提瓦特"创 ...

  9. php单机环境搭建,【完美西游网单服务端】新版单机一键安装游戏客户端带GM管理工具[附安装搭建教程]...

    [完美西游网单服务端]新版单机一键安装游戏客户端带GM管理工具[附安装搭建教程] 完美西游,2012年10月开启封测的一款客户端网游.<完美西游>推出了修真历练,守卫门派,梦桃源,火云洞, ...

最新文章

  1. 转 [JAVA] 使用 common-fileupload 实现文件上传
  2. etc下没有mysql_我在linux下,安装mysql的时候,cp support-files/my-medium.cnf /etc/my.cnf找不到my-medium.cnf...
  3. 二叉查找树的先序遍历,中序遍历,后序遍历
  4. python安装时没有选path怎么办,环境变量是个啥? 没有勾选Add to Path怎么办?
  5. c#提交事务的两种方法
  6. QDateTimeEdit使用
  7. 51Nod-1259-整数划分 V2
  8. 漫谈ASP.NET设计中的性能优化问题
  9. ## Asset Store(unity商店) 如何下载已购买的资源?*
  10. 变焦和对焦_在Randonautica内部,该应用程序可带领变焦器发现彩虹,尸体和隐藏的宝藏
  11. 易购考拉 The fourth day
  12. CUDA unknown error - this may be due to an incorrectly set up environment, e.g. changing env variabl
  13. 【缓存】@CacheEvict
  14. Java程序设计的基本结构 - 选择结构
  15. 计算机硬件检测数据恢复理论知识,计算机硬件检测维与数据恢复赛项规程.doc...
  16. 快速搭建一个本地的FTP服务器
  17. Java 转PPT为图片、PDF、SVG、XPS、ODP以及PPT和PPTX互转
  18. android 没有地磁, gps如何导航,室内没有GPS信号,要怎么精确导航?
  19. 迎难而上才是人生该有的状态,中国人民大学与加拿大女王大学金融硕士给予你前行的力量
  20. 03版计算机,office2003完整版电脑版

热门文章

  1. Linux系统调用-- mount/umount函数详解
  2. 【PC工具】大神开源项目-配色调色工具Colorpicker颜色选择器
  3. 安检x光机原理计算机实现,安检x光机成像原理介绍
  4. Android 8.0新特性(看这篇文章就够了)
  5. React16.2的fiber架构
  6. 在公司的局域网内,组长让你在自己的虚拟机部署项目,大家等着访问测试,该怎么办???...
  7. uva 10034 Freckles (kruskal||prim)
  8. JQUERY获取当前页面的URL信息
  9. 《Effective C#》读书笔记——条目28:提供粗粒度的互联网API使用C#表达设计
  10. 读“Agile Method – by Martin Fowler”总结和感想