当前位置: 首页 > article >正文

【C++boost::asio网络编程】有关服务端退出方法的笔记

有关服务端退出方法的笔记

  • C风格的信号关闭
  • boost::asio中的关闭方式

原来服务端的main函数如下

int main()
{
	try
	{
		boost::asio::io_context ioc;
		Server s(ioc, 8888);
		ioc.run();
	}
	catch (const std::exception&)
	{

	}
	return 0;
}

  上面弊端在于缺乏好的退出机制,目前,ioc.run() 会一直阻塞,直到 io_context 被显式地停止。然而,如果没有显式的退出信号或退出条件(如 SIGINT、SIGTERM 信号等),程序将无法优雅地退出。万一在运行时出现异常,或者程序需要在特定时机停止时,缺乏退出机制可能导致程序无法正常关闭。
  如果服务器程序无法响应中断信号或其他退出信号,可能会影响系统资源的释放,造成资源泄漏(如打开的网络连接、文件句柄等)。

C风格的信号关闭

#include <boost/asio.hpp>
#include <iostream>
#include "Session.h"
#include <thread>
#include <mutex>
#include <csignal>

bool bstop = false;
std::condition_variable cond_quit;
std::mutex mutex_quit;

void sig_handle(int sig)
{
	if (sig == SIGINT || sig == SIGTERM)
	{
		std::unique_lock<std::mutex> lock(mutex_quit);
		bstop = true;
		cond_quit.notify_one();
	}
}

int main()
{
	try
	{
		boost::asio::io_context ioc;
		std::thread net_work([&ioc] {
			Server s(ioc, 8888);
			ioc.run();
			});
		signal(SIGINT, sig_handle);
		signal(SIGTERM, sig_handle);
		while (!bstop)
		{
			std::unique_lock<std::mutex> lock(mutex_quit);
			cond_quit.wait(lock);
		}
		ioc.stop();
		net_work.join();
	}
	catch (const std::exception&)
	{

	}
	return 0;
}

  这里可以看到,不同于之前的主线程来进行轮询、收发数据的处理,这里采用了使用一个新线程net_work来负责原先主线程的任务,然后主线程负责监听SIGINTSIGTERM两个信号
  当程序正在运行的时候,如果想要终止程序,我们就可以通过向该进程发送信号来执行终止逻辑sig_handle。下面简单介绍一下主线程在干什么

signal(SIGINT, sig_handle);
signal(SIGTERM, sig_handle);
while (!bstop)
{
	std::unique_lock<std::mutex> lock(mutex_quit);
	cond_quit.wait(lock);
}
ioc.stop();
net_work.join();

  在while循环内部,定义了一个std::unique_lock<std::mutex>类型的变量,这个unique_lock主要就是和条件变量condition_variable 来搭配使用的。当发现当发现bstop(用来判断当前进程是否需要终止)为假时,进行循环,然后让主线程在条件变量下等待
可以不设置条件变量一直死循环吗?
  这么做虽然逻辑上可以,但是一直死循环会导致当前线程一直占用CPU资源造成资源浪费的现象,比较好的处理方案就是让该线程进入阻塞状态。然后我们给改进程发送信号时,执行sig_handle函数

void sig_handle(int sig)
{
	if (sig == SIGINT || sig == SIGTERM)
	{
		std::unique_lock<std::mutex> lock(mutex_quit);
		bstop = true;
		cond_quit.notify_one();
	}
}

  在这个函数中,会将bstop设置为true,表示整个程序应该要终止了,然后去唤醒主线程告诉它要去进行收尾的逻辑

ioc.stop();
net_work.join();

  回到主线程,退出循环之后,停止掉ioc,然后去等待回收net_work线程,回收之后再退出,此时整个程序也就安全退出了

boost::asio中的关闭方式

int main()
{
	try
	{
		boost::asio::io_context ioc;
		boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);
		signals.async_wait([&ioc](auto, auto) {
			ioc.stop();
			});
		Server s(ioc, 8888);
		ioc.run();
	}
	catch (const std::exception&)
	{

	}
	return 0;
}
boost::asio::signal_set signals(ioc, SIGINT, SIGTERM);

  这一行创建了一个 boost::asio::signal_set 对象signals。signal_set 用于注册对特定信号(如中断信号 SIGINT 或终止信号 SIGTERM)的异步处理。这里注册了 SIGINT(通常是按下 Ctrl+C 时触发)和 SIGTERM(终止进程的信号)信号。
  signals 会监听这些信号,并触发相关的回调函数。

signals.async_wait([&ioc](auto, auto) { ioc.stop(); });

  这行代码使用了 async_wait 来等待信号的异步触发。回调函数会在 SIGINT 或 SIGTERM 信号到达时被调用。在回调函数内部,调用了 ioc.stop(),这会停止 io_context 的事件循环。当信号到达时,ioc.stop() 会中断事件循环的运行,允许程序优雅地退出


http://www.kler.cn/a/454053.html

相关文章:

  • Cursor提示词
  • 【Three.js基础学习】33.Halftone Shading shaders
  • MySQL45讲 第三十六讲 为什么临时表可以重名?——阅读总结
  • DP动态规划+贪心题目汇总
  • 【ES6复习笔记】解构赋值(2)
  • 5.近实时数仓数据更新和ID 管理上的优化方案
  • 华为OD E卷(100分)39-最长子字符串的长度(二)
  • SpringBoot + HttpSession 自定义生成sessionId
  • 数据中台从centos升级为国产操作系统后,资源增加字段时,提交报500错误
  • 网页中字体图标Fontawesome的使用
  • linux-22 目录管理(二)rmdir命令,删除目录
  • 白牛招投标数据库介绍
  • 什么是Web应用防火墙,简称:WAF(Web Application Firewall)
  • 前端请求跨域问题
  • Docker部署GitLab服务器
  • UDP的报文结构和特点
  • leetcode1110删点成林
  • MATLAB中UWB工具箱的使用建议
  • 解决pycharm无法识别miniconda
  • AI Weekly『12月16-22日』:OpenAI公布o3,谷歌发布首个推理模型,GitHub Copilot免费版上线!
  • VisualRules华为应用场景介绍
  • jquery固定折叠侧边栏菜单插件
  • Oracle一些基础知识
  • 【C++ 基础】从C到C++有哪些变化
  • hadoop中hive本地模式安装mysql源不成功
  • 【漫话机器学习系列】022.微积分中的链式求导法则(chain rule of Calculus)