[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…...
MySQL8.0 optimizer_switch变化
Optimizer_switch变量是支持对优化器行为的控制。是一组值标志,每个标志都有一个on或off的值,以指示是否启用或禁用相应的行为。 MySQL8.0里除了熟悉的hash join重大变化之外,其他方面也有优化。 mysql> SHOW VARIABLES LIKE OPTIMIZER_…...
Web--Maven
1.maven管理项目的区别 2. 安装后,conf目录下的setting文件中,对本地仓库的配置 此处可替换成自定义的本地仓库地址,默认为c:/user/17860/.m2/repository(我的电脑上的) 3.maven项目的标准目录结构 4.项目的生命周期 5.Maven概…...
深入理解MySQLⅢ -- 锁与InnoDB引擎
文章目录锁概述全局锁表级锁表锁元数据锁意向锁行级锁行锁间隙锁&临键锁InnoDB引擎逻辑存储结构架构内存结构磁盘结构后台线程事务原理redo logundo logMVCC锁 概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,除传统的计算资源&#x…...
Win11电脑速度慢、延迟高怎么办?
作为新版的系统,Windows 11还需要更多的时间完善。不少用户反映升级了Win11后反而感觉速度慢,还有延迟或死机现象。 如果你使用Win11系统时也有这种感觉,那这篇文章就是为你提供的。 问题可能出在系统存储容量低、驱动程序已过时࿰…...
【双指针问题】977. 有序数组的平方
Halo,这里是Ppeua。平时主要更新C语言,C,数据结构算法......感兴趣就关注我吧!你定不会失望。 🌈个人主页:主页链接 🌈算法专栏:专栏链接 我会一直往里填充内容哒! &…...
Meta AR眼镜主管:正开发史无前例的AR,但要解决很多困难
前不久,Meta CTO Andrew Bosworth在个人博客上“怒斥”公司内部不够专注,应该将资源投入在有核心竞争力、高投资回报率的业务上,而不是开发取悦用户却不赚钱的产品。尽管删除一些小众功能后,用户可能会不满,但为了让Me…...
Docker 搭建KingbaseES主备流复制
author: aming email: jikcheng163.com title: Docker 安装KingbaseES读写分离集群 creation_date: 2023-02-16 13:59 Last modified date: 2023-02-16 19:18 tags: Docker 安装KingbaseES读写分离集群 File Folder with relative path: reading notes/doc/Docker技术入门与实战…...
java易错题锦集四
effective java 不要再构造方法中启动任何线程 g new GameServer(); g.start();构造器无返回值,但是不能void修饰 字符串 String是包装类型吗?答案: 不是 对应的基本类型和包装类如下表: 基本数据类型 包装类 byte Byte bool…...
每天10个前端小知识 【Day 17】
前端面试基础知识题 1.使用原生js实现以下效果:点击容器内的图标,图标边框变成border:1px solid red,点击空白处重置 const box document.getElementById(box); function isIcon(target) { return target.className.includes(icon); } b…...
Python语言零基础入门教程(二十三)
16、Python os.fpathconf() 方法 概述 os.fpathconf() 方法用于返回一个打开的文件的系统配置信息。 Unix上可用。 语法 fpathconf()方法语法格式如下: os.fpathconf(fd, name)参数 fd – 打开的文件的描述符。 name – 可选,和buffersize参数和Pyt…...
南昌电商网站设计/提高工作效率心得体会
您可以使用StringDecoder从HttpRequest中的“List of Int”转换为“String”.因为无论你发送json,纯文本还是png,Dart总是以数据的形式发送数据“服务器列表”到服务器.另一种方法是使用在Heroku Steam上测试的Streams(http://www.dartlang.org/articles/feet-wet-streams/)v0.…...
政府门户网站等保建设方案/网站排名优化手机
CocosCreator零基础制作游戏《极限跳跃》七、制作游戏结束场景并实现场景切换前面我们实现了游戏的碰撞检测,碰到障碍物我们的角色就会死掉并开始掉落,角色掉落到屏幕底部时候游戏结束,并跳到结束场景。我们在资源管理器新建GameOver场景。双…...
做印刷网站公司/亚马逊开店流程及费用
提供一份官方的译文。翻译也挺辛苦的!! 6.4 Using Connector/Net with Connection Pooling 6.4在Connector/Net中使用连接池 The Connector/Net supports connection pooling for better performance and scalability with database-intensive applicati…...
旅游主题网站策划书/icp备案查询
服务器换机房后cacti监控不出图故障排查 环境介绍: 因为业务需要,公司在深圳机房的几台服务器搬迁到中山机房,由于监控服务器放在佛山,因此采用如下图的方式来对中山机房的机器进行监控: 佛山的监控系统采用cactinagio…...
做彩平图的素材那个网站有/网站设计制作公司
http://www.iteye.com/topic/344876 http://www.goldendoc.org/2011/06/juc_concurrenthashmap/实现原理 锁分离 (Lock Stripping) ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。Co…...
香港疫情最新数据/西安seo学院
点击蓝字关注我?获取 高效/实用/好玩 的工具软件和教程前言输入法对我们来说无疑是最基本的必备软件了,因此选一个不流氓且无广告的输入法相当重要。谁都不想电脑右下角时不时地弹一个广告,尤其是618和双十一时,拦截软件都拦不住,…...