[C++]服务器与客户端建立连接与检测断开的demo
该程序在IP127.0.0.1以及端口5000环境下测试
有一段时间没有在Windows下用C++进行网络编程了,这段日子都在做QT的网络编程和OpenCV的图像识别。
今天重新写个Windows下C++的,基于TCP的双端连接建立与断开检测的demo,巩固下自己Windows下的网络编程知识点。
在下面的代码共有四个类,一个内部结构体,以下是他们的介绍。
WebException类可以忽略,是一个异常类,用于反馈意外情况。
WebBase类是服务端和客户端的基类,用于初始化共同的基本数据。
Server类是服务端类,用于接收客户端连接。
Client类是客户端类,用于连接服务端。Server类的内部结构体ClientSocket,用以保存已经连接到服务端的客户端Socket。
由于只是做个简单的相互检测连接与断开的demo,所以整个程序就全在这一个cpp中了。
该demo的主要功能是:
- 服务器能被连接十次,服务器可以检测客户端断开与否。
- 客户端连接上服务器后,客户端可以检测到与服务器失联与否。
服务端的整体思路是:
主线程负责检测客户端的连接请求,服务端同意连接获取到客户Socket后,以clock()获取到的值当作客户id,以id为key,将客户Socket保存到cliSockets这个map中;
保存好客户Socket后,开启一条线程用以检测连接是否丢失,如果丢失了(暂不考虑重连),则回收客户的Socket与相应线程资源;
此外,为了了解服务端关闭后,客户端的失联处理,服务端被设置成只能连接十次;
十次后关闭服务端,服务端这次的主动关闭将回收所有存活的客户端Socket和相应的线程资源。
安全回收后,服务端正式关闭。
客户端的整体思路是:
主线程负责检测连接上服务端,每秒尝试一次连接,连接成功获取到服务端Socket后开启一条线程用以检测连接是否丢失,如果丢失了(暂不考虑重连),则回收服务端的Socket与相应线程资源;
如果客户端发现在主动断开与服务端的连接前就已经无法联系服务端,那么将回收服务端Socket和相应的线程资源。
安全回收后,客户端正式关闭。
#pragma comment(lib,"Ws2_32.lib")
#include <iostream>
#include <Windows.h>
#include <thread>
#include <conio.h>
#include <map>
using namespace std;
//自定义的异常类,用来反馈网络异常
class WebException {
public:WebException(int error):error(error), errorMsg("未知异常") {}WebException(int error,string errorMsg) :error(error), errorMsg(errorMsg) {}virtual void what()const {switch (error) {default:cout << errorMsg << endl;}}
private:int error;string errorMsg;
};
class WebBase {
protected://设定监听端口WebBase():port(5000){}virtual ~WebBase() {closesocket(_socket);//关闭套接字cout << "套接字关闭完成..." << endl;WSACleanup();//清理资源cout << "DLL资源已清理..." << endl;system("pause");}
public:virtual void init() {wVersionRequested = MAKEWORD(2, 2);//计算版本号if (0 != WSAStartup(wVersionRequested, &ws)) throw WebException(0, "初始化DLL失败");cout << "初始化DLL完成..." << endl;_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);memset(&addr, 0, sizeof(addr));//初始化地址结构为0addr.sin_family = AF_INET;//赋值addr.sin_port = htons(port);//赋值端口信息addr.sin_addr.S_un.S_addr = INADDR_ANY;//表示32位IPv4地址,以网络字节序保存}WORD wVersionRequested;//版本号WSADATA ws;//记录WinSock DLL信息SOCKET _socket;//创建套接字const u_short port;//端口号struct sockaddr_in addr;//地址信息
};
class Server:public WebBase {
public:~Server() {cout << "当前存活的客户端连接数:" << cliSockets.size() << endl;//非强迫地要求所有线程停止活动map<clock_t, pair<bool, thread>>::iterator itr = cliThreads.begin();while (itr != cliThreads.end()) {cliThreads[itr->first].first = false;++itr;}//要求完之后,等待所有线程结束,此处不用资源释放,资源释放在线程中完成itr = cliThreads.begin();while (itr != cliThreads.end()) {cliThreads[itr->first].second.join();cliThreads.erase(itr->first);itr = cliThreads.begin();}cout << "服务器已关闭所有客户端连接" << endl;}void init() {cout << "正在部署服务器..." << endl;WebBase::init();if (SOCKET_ERROR == bind(_socket, (const sockaddr*)(&addr), sizeof(addr)))throw WebException(0, "绑定失败");cout << "套接字绑定成功..." << endl;if(SOCKET_ERROR == listen(_socket, 5))//设置服务端网络监听,队列为5throw WebException(0, " 监听设置失败");cout << "正在监听..." << endl;char buff[128];gethostname(buff, sizeof(buff)); cout << "服务器IP:" << inet_ntoa(*(in_addr*)*(gethostbyname(buff)->h_addr_list)) << endl;cout << "服务器等待连接请求中..." << endl;int live_num = 10;while (live_num--) {ClientSocket cliSocket;int len = sizeof(cliSocket.addr);cliSocket._socket = accept(_socket, (struct sockaddr*)&cliSocket.addr, &len);//接受连接请求Sleep(1);clock_t id = clock();cliSockets[id] = cliSocket;cliThreads[id] = pair<bool,thread>(true,thread(&Server::testConRun, this, id));cout << "客户(" << id << ")建立起与服务器的连接" << endl;}shutdown(_socket, 3);cout << "已完成十次连接,服务器自动关闭" << endl;}
private:void testConRun(clock_t id) {//每两秒1次连接检测int num = 0;while (cliThreads[id].first) {++num;if (num >= 10) {num = 0;if (SOCKET_ERROR == send(cliSockets[id]._socket, "t", sizeof("t"), 0)) {cout << "客户(" << id << ")断开了与服务器的连接" << endl;closesocket(cliSockets[id]._socket);cout << "关闭了客户(" << id << ")的Socket" << endl;cliSockets.erase(id);//这里让线程与thread类分离,使得erase掉thread类不影响线程//return后,分离了的线程会自己自动销毁cliThreads[id].second.detach();cliThreads.erase(id);return;}}Sleep(200);}if (!cliThreads[id].first) {cout << "服务器断开了与客户(" << id << ")的连接" << endl;closesocket(cliSockets[id]._socket);cout << "关闭了客户(" << id << ")的Socket" << endl;cliSockets.erase(id);}}struct ClientSocket {struct sockaddr_in addr;//地址信息SOCKET _socket;//创建套接字};map<clock_t, Server::ClientSocket> cliSockets;map<clock_t, pair<bool, thread>> cliThreads;
};
class Client:public WebBase {
public:Client():testCon(nullptr),isTestConRun(true){}~Client() {isTestConRun = false;testCon->join();closesocket(_socket);cout << "关闭了客户端的Socket" << endl;testCon.release();}void init() {cout << "正在部署客户端..." << endl;WebBase::init();addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");//表示32位IPv4地址,以网络字节序保存while (SOCKET_ERROR == connect(_socket, (const sockaddr*)&addr, sizeof(addr))) {cout << "连接服务器失败" << endl;Sleep(1000);}cout << "连接服务器成功,输入任意键以断开链接" << endl;testCon.reset(new thread(&Client::testConRun,this));_getch();}
private:void testConRun() {//每两秒1次连接检测int num = 0;while (isTestConRun) {++num;if (num >= 10) {num = 0;if (SOCKET_ERROR == send(_socket, "t", sizeof("t"), 0)) {cout << "服务器断开了与客户端的链接" << endl;return;}}Sleep(200);}}unique_ptr<thread> testCon;volatile bool isTestConRun;
};
//启动服务端
void startServer() {Server server;try {server.init();}catch (WebException& e) {e.what();}catch (...) {cout << "未知其他异常";}
}
//启动客户端
void startClient() {Client client;try {client.init();}catch (WebException& e) {e.what();}catch (...) {cout << "未知其他异常";}
}
int main()
{while (true) {system("cls");cout << "请选择端的类型:" << endl;cout << "1.服务端" << endl;cout << "2.客户端" << endl;cout << "0.退出" << endl;cout << "请输入:" << endl;switch (_getch()) {case '1':system("cls"); startServer();break;case '2':system("cls"); startClient();break;case '0':return 0;}}
}
相关文章:
[C++]服务器与客户端建立连接与检测断开的demo
该程序在IP127.0.0.1以及端口5000环境下测试 有一段时间没有在Windows下用C进行网络编程了,这段日子都在做QT的网络编程和OpenCV的图像识别。 今天重新写个Windows下C的,基于TCP的双端连接建立与断开检测的demo,巩固下自己Windows下的网络编程…...
包教包会vue3+ts状态管理工具pinia
一、Pinia介绍 定义:pinia是和vuex一样的状态管理工具 语法:和 Vue3 一样,它实现状态管理有两种语法:选项式API 和 组合式API 支持:vue2、typeScript、devtools 二、使用步骤 1.安装 pnpm add pinia yarn add pin…...
Generated columns cannot be used in COPY
错误如下DBD::Pg::db do failed: ERROR: column "transtype" is a generated columnsec., avg: 2520 recs/sec), REPORTSINTERMEDIATETABLE in progress.DETAIL: Generated columns cannot be used in COPY. at /usr/local/share/perl5/Ora2Pg.pm line 15125.FATAL: …...

Amazon S3简介
前言: 这段时间来到了某大数据平台,做平台技术底座封装和一些架构等等,有结构化数据也有非结构数据,涉及到很多技术,自己也私下花时间去研究了很多,有很多纯技术类的还是需要梳理并记录,巩固以及…...

MySQL索引类型——有五种
文章目录前言一、MySQL中的索引类型有以下几种1.1 普通索引1.1.1 直接创建索引1.1.2 修改结构的方式添加索引1.1.3 创建表的时候同时创建索引1.1.4 删除索引1.2 唯一索引1.2.1 创建唯一索引1.2.2 修改表结构1.2.3 创建表的时候直接指定1.3 主键索引1.4 组合索引1.5 全文索引1.5…...
CloudCompare 二次开发(5)——非插件中的PCL环境配置(均匀采样为例)
目录 一、概述二、CMakeLists.txt三、源码编译四、代码示例五、结果展示一、概述 在进行CloudCompare二次开发的时候,可以直接在CloudCompare的核心功能中添加自己的算法,比插件式的算法集成要方便得多。因此,这里主要记录CloudCompare非插件式二次开发配置PCL,并给出具体开…...

停车辅助系统的技术和变化
各种各样的停车辅助系统已经存在了很长时间,但用户经常在不知道什么技术以及它是如何工作的情况下使用它们。 今天我们依次来谈谈停车辅助系统是什么,怎么发展以及如何应用的。 1.手信号 您可能会想,“为什么手信号是停车辅助系统&#x…...

扬帆优配|日均客运量恢复,民航业加速复苏,外资买入2股超亿元
春运民航客运量康复至疫情前七成。 2月16日,民航局举行2月例行新闻发布会。会上介绍,自1月7日至2月15日,春运40天,民航运送旅客5523万人次,日均客运量138万人次,同比去年春运添加39%,康复至2019…...
【PyTorch】教程:torch.nn.ModuleDict
Containers-ModuleList CLASS torch.nn.ModuleDict(modulesNone) 将所有的子模块放到一个字典中。 ModuleDict 可以像常规 Python 字典一样进行索引,但它包含的模块已正确注册,所有 Module 方法都可以看到。 ModuleDict 是一个有序字典。 Parameters …...

Git、小乌龟、Gitee的概述与安装应用超详细(组长与组员多人开发版本)
目录 一、概述 1.什么是Git? 2.Git历史来源 3.Git的优点? 4.什么是版本控制? 5.版本控制工具种类? 6.Git工作机制 7.Git、小乌龟、Gitee、凭据管理器的简单介绍 二、Git下载安装 下载Git 安装Git 安装完成后查看版本 三、下载小…...

【java 高并发编程之JUC】高阶JUC特性总结
1 线程中断机制 1.1 什么是中断? 首先 一个线程不应该由其他线程来强制中断或停止,而是应该由线程自己自行停止。所以,Thread.stop, Thread.suspend, Thread.resume 都已经被废弃了。 其次 在Java中没有办法立即停止一条线程,然…...

行业分析| 智能无人自助设备
智能无人自助设备运用二维码技术、音视频通信技术和AI智能技术等相结合,提供了无人超市、自动售货机、智能快递柜等。当下很多商业地区或社区,都放置了智能无人自助设备,不仅可以为商家节省时间和精力、提升运营环境,也可以为众多…...

使用契约测试得不偿失?试试契约先行开发
契约维护的难题 如今微服务凭借其灵活、易开发、易扩展等优势深入人心,不同服务之间的集成和交互日渐繁多且复杂。这些服务之间交互的方式是多样的,常见的有 HTTP 请求和消息队列。在它们交互的过程中,会有服务的版本演进,交互信…...

函数编程之Function
文章目录前言一、Function是什么?二、Function 怎么用?1.简单使用2.真正的强大之处总结前言 在java8之后,我已经习惯了开始用stream()方式编程,但是对于新引入的其他功能,还是不清楚,今天经历了一个编程问题后,让我对于Function() 这个函数有了新的认知; 一、Func…...

Vue 双向绑定原理
Vue2 双向绑定原理 mvvm 双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来 劫持各个属性的 setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。 几个要点: 1&#…...

【数据治理-03】无规矩不成方圆,聊聊如何建立数据标准
无规矩,不成方圆!数据标准(Data Standards)是保障数据的内外部使用和交换的一致性和准确性的规范性约束,作为数据治理的基石,是绕不开的一项工作,如此重要的活如何干,咱们一起聊聊。…...
dos常用命令
DOS(磁盘操作系统)命令,是DOS操作系统的命令,是一种面向磁盘的操作命令,主要包括目录操作类命令、磁盘操作类命令、文件操作类命令和其它命令。 使用技巧 DOS命令不区分大小写,比如C盘的Program Files&…...
解决原生template标签在Vue中失效的问题
文章目录前言一、事件未绑定的原因二、如何处理原生template标签总结前言 需要原生Javascript three.js的数据标注平台加入Vue框架. 本来挺顺利的, 我直接在mounted周期做了初始化, 然后剩下的操作还是交给JavaScript文件执行, 最后发现里面有很明显的事件触发问题. 一、事件…...

节能降耗方案-医院能源管理系统平台的研究与应用分析
摘要:综合性医院作为大型公共机构,能耗高的问题日益突出,构建能耗监控平台对医院能耗量化管理以及效果评估已经成为迫切需要。建立智能能耗监控平台,对采集的能耗数据进行分析,实现对医院能耗平台监控,为医…...

Redis学习【7】之发布_订阅命令和事务
文章目录一 发布/订阅命令1.1 消息系统1.2 subscribe1.3 psubscribe1.4 publish1.5 unsubscribe1.6 punsubscribe1.7 pubsub1.7.1 pubsub channels1.7.2 pubsub numsub1.7.3 pubsub numpat二 Redis 事务2.1 Redis 事务特性Redis 事务实现2.1.1 三个命令2.1.2 基本使用2.2. Redi…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...

解析“道作为序位生成器”的核心原理
解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制,重点解析"道作为序位生成器"的核心原理与实现框架: 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...

在Zenodo下载文件 用到googlecolab googledrive
方法:Figshare/Zenodo上的数据/文件下载不下来?尝试利用Google Colab :https://zhuanlan.zhihu.com/p/1898503078782674027 参考: 通过Colab&谷歌云下载Figshare数据,超级实用!!࿰…...