[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…...
wordpress资讯自媒体中文主题/营销推广费用方案
✿今日屋主✿户型:两室一厅面积:77㎡风格:北欧全部花费:40万屋主是一个美食博主,一位自称爷的姑娘,也是一个标准的“颜控”。为了满足自己梦想中的开放式的大厨房有自然光的餐厅(主要是要吃的开…...
一个彩票网站建设/如何优化
和CMMI 1.3的评估相比,在CMMI 2.0评估时必须提交性能报告。 性能能报究竟是何方神圣呢? 性能报告并不神秘!它就是你实效改进的故事! 为什么这么讲呢?请看性能报告中的内容: 性能报告围绕组织的业务目标讲…...
国外医院网站设计/正规seo排名公司
对用户历史行为进行建模: sequence feature;使用attention方法;...
沈阳建设局网站首页/网站推广广告
流程控制:顺序结构、分支结构(选择结构)、循环结构。<?php /*** 流程控制:* 顺序结构、分支结构(选择结构)、循环结构** 1、分支结构:* 1.1、单一条件分支结构(if)* 1.2、双向条件分支结构(else)* 1.3、多向条件分支结构(elseif、switch)…...
找人做事的网站/google seo 优化招聘
前言JDK的并发包中提供了几个非常有用的工具类,这些工具类给我们在业务开发过程中提供了一种并发流程控制的手段,本文会基于实际应用场景介绍如何使用Semaphore,以及内部实现机制。Semaphore是什么Semaphore也叫信号量,在JDK1.5被…...
零基础网站制作视频教程/中国万网域名注册官网
问题 使用前后端分离模式开发项目时,往往会遇到这样一个问题 -- 无法跨域获取服务端数据 这是由于浏览器的同源策略导致的,目的是为了安全。在前后端分离开发模式备受青睐的今天,前端和后台项目往往会在不同的环境下进行开发,这时…...