【Linux系统化学习】守护进程 | 序列化和反序列化

目录

前言

守护进程

会话

进程组

setsid系统调用

守护进程系统调用

再谈协议

序列化和反序列化

Json


前言

上两篇文章我们所编写的服务器,并算不上真正意义上的服务器一般的服务器都是要随时能够访问的,就像我们在任何时间段都可以打开抖音获取视频资源;要想实现只需要将我们的进程变成守护进程(精灵进程)。

守护进程

会话

当我们使用xshell登录我们自己的服务器时操作系统会给登录用户提供:

  1. 命令行解释器(bash)
  2. 提供一个终端(给用户提供命令解析服务)

这个终端就是会话

进程组

当我们在同时运行多个进程时,shell就会将这几个进程归为一个组即进程组;因此进程组是一组相关联进程的集合,并且每一个进程组的第一个进程的ID为进程组ID。当只有一个进程启动的时候称为自成进程组。

前面说过任何时刻一个会话内部,可以包含很多进程组,但是默认时刻只允许一个进程组在前台也就是前台进程。当运行我们的服务器时,就是这种前台进程的状态;但是当我们退出xshell时,进程也就随之终止,被释放资源了;达不到一直运行的状态;因此我们可以将我们的进程转化为守护进程。

setsid系统调用

setsid 执行以下操作:

  1. 创建新的会话:它创建了一个新的会话,与当前的终端会话分离开来。这意味着即使当前的终端关闭,该会话也会继续存在。

  2. 设置当前进程为会话领导者setsid 将当前进程的进程ID设置为新会话的领导者(session leader)。这意味着当前进程成为了新会话中的第一个进程,并且没有父进程。

  3. 脱离终端:因为新的会话已经创建,setsid 将当前进程从其原始的控制终端分离开来。这样即使启动进程的终端关闭,该进程也不会受到影响。

但是单个的自成进程组是不可以调用这个系统调用的,因此我们可以创建子进程后父进程直接退出,让1号进程领养子进程,在子进程中调用这个系统调用。

Daemon.hpp

#pragma once#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>const char *root = "/";
const char *dev_null = "/dev/null";void Daemon(bool ischdir, bool isclose)
{// 1. 忽略可能引起程序异常退出的信号signal(SIGCHLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);// 2. 让自己不要成为组长if (fork() > 0)exit(0);// 3. 设置让自己成为一个新的会话, 后面的代码其实是子进程在走setsid();// 4. 每一个进程都有自己的CWD,是否将当前进程的CWD更改成为 / 根目录if (ischdir)chdir(root);// 5. 已经变成守护进程啦,不需要和用户的输入输出,错误进行关联了if (isclose){close(0);close(1);close(2);}else{// 这里一般建议就用这种int fd = open(dev_null, O_RDWR);if (fd > 0){dup2(fd, 0);dup2(fd, 1);dup2(fd, 2);close(fd);}}
}

 注:

  • 要忽略可能引起进程异常终止的信号
  • 不可以使用三个标准IO流
  • 将标准IO流重定向,或者写入到系统的dev_null特殊文件中,IO对于这个文件都没有用

守护进程系统调用

上面的是我们通过系统调用setsid自主 实现的一种守护进程的方式,在系统中有直接的创建守护进程的系统调用。

int daemon(int nochdir, int noclose);

参数

  • nochdir:如果为非零值,表示不改变当前工作目录为根目录(/)。如果为零,表示将当前工作目录改变为根目录。
  • noclose:如果为非零值,表示不关闭标准输入、标准输出和标准错误文件描述符。如果为零,表示关闭这些文件描述符。

返回值

  • 如果成功,返回 0。
  • 如果失败,返回 -1,并设置 errno。

工作原理

  • 首先,daemon 函数会调用 fork 来创建一个子进程。
  • 子进程会调用 setsid 来创建一个新的会话,并成为该会话的领导者。
  • 如果 nochdir 参数为零,子进程会将当前工作目录更改为根目录(/)。
  • 如果 noclose 参数为零,子进程会关闭标准输入、标准输出和标准错误文件描述符。
  • 最后,子进程会返回 0,然后父进程退出。

 工作原理和我们上面自主实现的工作原理一模一样。

再谈协议

前面的文章我们简单说过协议就是对于通信双方来说就一种商量好的约定;但是socket api的接口都是按照”字符串“的方式来发送和接受的,如果我们要传送结构化的数据怎么办。

例如:如我们今天想制作一个网络版本的计算器;作为客户端来说我们要发送的是两个操作数和一个操作符,作为接收端我们收到的数据也是两个操作数和一个操作符,将发来的数据进行处理后;服务端我们是不是要发送运算结果和运算状态,在发送给客户端。

通过上面的例子我们可以将接收和发送的数据,设计为一个结构体;将这个结构体作为传输的基本数据结构,让客户端和服务端通信双方都遵守这个规则即可,这就是协议;

序列化和反序列化

在网络部分开始的时候我们就提到过TCP协议是面向字节流的,如果今天我们要使用TCP协议通信传输结构化的数据来实现上面的网络版本计算机,会遇到很多问题。

  • 对于语言来说,如果通信双方是使用不同的语言来编写的;对于不同的语言结构体定义和使用都不同;
  • 对于平台来说:结构体含有内存对齐,不同编译器和不同平台对结构体的内存布局可能有所不同,这可能导致在通信过程中出现数据的错位或填充。
  • 对于协议来说:TCP协议是面向字节节流的,如果只能发固定的字节,而这个固定的字节却不能支持一个完整的结构体,对于服务端来说如何处理不完整的数据

基于上面的问题,作为客户端就要将定义好的结构化数据转化为”字符串“字节流,这个过程就是序列化。

作为服务端我们收到的是”字符串“字节流,我们要将这个字节流转化为通信双方约定好的结构化数据,这个过程就是反序列化。

Json

简单来说序列化和反序列化就是将要发送的数据转化为字符串,将接收的数据转化为结构化的数据。也就是对字符串进行操作,如果我们自己实现这个过程,很麻烦也很容易出错;我们可以使用Json、protobuff、xml用来代替我们自主实现繁琐的字符转换。

注意:

  • TCP协议是全双工的,并且作为服务器和客户端双方是对等的;都可以进行收发消息。
  • 应用层用户通过write、send或者read、recv进行收发消息时只是将消息拷贝到内核TCP协议发送或者接收的缓冲区中、由协议决定缓冲区中的数据什么时候发送、发送多少、出错了怎么办;哪些函数只是拷贝函数。
  • TCP实际通信的时候其实是双方操作系统之间进行通信
  • 在用户层面你认为你发送了多少字节,但是对方比一定就要收多少字节
  • 自主实现协议的时候一定要明确字节流和字节流之间的边界,确保接收端读到完整的一个字节流
  • 生产者消费者模型的一种,任意一方向网络中放数据,一方从网络中取数据

今天对Linux中守护进程、序列化和反序列化的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/697245.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

部署达梦数据库主从配置详细操作DM8

服务器配置 主库 192.168.81.128 实例名 dm-1 从库 192.168.81.129 实例名 dm-2 以下安装部署主从服务器都操作 关闭防火墙 systemctl stop firewalld && systemctl disable firewalld 注意安装前必须创建 dmdba 用户&#xff0c;禁止使用 root 用户安装数据库。…

参加了深圳线下组织的商业沙龙,收获颇丰

能参加本次商业沙龙也本是一连串的事情导致的&#xff0c;听我慢慢道来&#xff1a; 大概在4.13之前无意收到忘了谁发的短信了&#xff0c;说有个啥AI的报告会&#xff0c;然后我就报名了&#xff1a; 会上大佬还是挺多的&#xff0c;来了好多各界的老板和政府的领导&#xff…

class常量池、运行时常量池和字符串常量池的关系

类常量池、运行时常量池和字符串常量池这三种常量池&#xff0c;在Java中扮演着不同但又相互关联的角色。理解它们之间的关系&#xff0c;有助于深入理解Java虚拟机&#xff08;JVM&#xff09;的内部工作机制&#xff0c;尤其是在类加载、内存分配和字符串处理方面。 类常量池…

[动态规划] 完美覆盖

描述 一张普通的国际象棋棋盘&#xff0c;它被分成 8 乘 8 (8 行 8 列) 的 64 个方格。设有形状一样的多米诺牌&#xff0c;每张牌恰好覆盖棋盘上相邻的两个方格&#xff0c;即一张多米诺牌是一张 1 行 2 列或者 2 行 1 列的牌。那么&#xff0c;是否能够把 32 张多米诺牌摆放…

软件测试,功能测试转测开容易吗?

一、从这个问题&#xff0c;我能读出一些信息如下&#xff1a; 1、不知道您从事测试工作多久了&#xff0c;可以看出您特别羡慕测试开发工程师&#xff1b; 2、 您可能一直从事功能测试工作&#xff0c;工作模式或大环境下&#xff0c;被中了草&#xff0c;想学习测试开发相关…

Today At Apple 2024.05.12 上海静安 制作属于自己的表情符号

官网&#xff1a; https://www.apple.com/today/Apple 亚洲第一大商店&#xff1a;Apple 静安零售店现已在上海开幕如下预约课程&#xff1a;下载 Apple Store&#xff08;不是app store&#xff09;&#xff0c;点击课程预约笔记&#xff1a;Today At Apple Notes果粉加群 &am…

测试项目实战--安享理财2(Jmeter接口测试)

说明&#xff1a; 1.访问地址&#xff1a; 本项目实战使用的是传智播客的安享理财项目&#xff08;找了半天这个项目能免费用且能够满足测试实战需求&#xff09; 前台&#xff1a;http://121.43.169.97:8081/ 后台&#xff1a;http://121.43.169.97:8082/ &#xff08;点赞收藏…

vue3 - 150

目录 vue优势使用方式编写vue代码指令响应式数据其他 vue优势 功能全面生态好&#xff0c;语法简洁效率高&#xff0c;免去 DOM 操作苦&#xff0c;开发重任一肩挑&#xff01; 使用方式 1.通过cdn引入来将 Vue 应用到整个页面 2.或通过官方脚手架 create-vue来创建完整的v…

AI可以成为重新点燃数字化转型的催化剂

你是如何陷入困境的 数字化转型对很多人来说意味着很多事情。是为了变得更有效率吗&#xff1f;升级工具&#xff1f;向客户提供新的数字产品&#xff1f;采用数据驱动策略&#xff1f;改变内部文化&#xff1f;我们并不总能看到这些能够团结组织的统一目标。这种缺乏重点常常…

迄今为止最全- 前端性能优化

简介 当我们说前端性能优化的时候&#xff0c;指的可能是不同场景的性能优化。前端涉及性能优化的场景主要有&#xff1a; 项目构建性能优化 页面性能优化 加载时性能优化 运行时性能优化 构建性能主要指构建速度&#xff0c;优化方法和打包工具直接相关&#xff0c;主要…

【React】redux开发者工具redux-devtools-extension的安装和使用

前言 redux-devtools-extension: 是一个用于Redux的开发者工具扩展。适合用于需要调试和监控Redux应用的状态管理。特点是可以提供实时的状态查看、行动日志和错误检测等 安装 chrome安装redux-devtools-extension 项目中安装并引入redux-devtools-extension yarn add re…

十一、Redis持久化-RDB、AOF

Redis提供了两种持久化数据的方式。一种是RDB快照&#xff0c;另一种是AOF日志。RDB快照是一次全量备份&#xff0c;AOF日志是连续的增量备份。RDB快照是以二进制的方式存放Redis中的数据&#xff0c;在存储上比较紧凑&#xff1b;AOF日志记录的是对内存数据修改的指令文本记录…