[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…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用
文章目录 问题现象问题原因解决办法 问题现象 macOS启动台(Launchpad)多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显,都是Google家的办公全家桶。这些应用并不是通过独立安装的…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
