Linux网络编程—Day10

news2025/1/18 6:52:24

Linux服务器程序规范

  • Linux服务器程序一般以后台进程形式运行。后台进程又称守护进程。它没有控制终端,因而也不会意外接收到用户输入。 守护进程的父进程通常是init进程(PID为1的进程);
  • Linux服务器程序通常有一套日志系统,它至少能输出日志到文件,有的高级服务器还能输出日志到专门的UDP服务器。大部分后台进程都在/var/log目录下拥有自己的日志目录;
  • Linux服务器程序一般以某个专门的非root身份运行。比如mysqld、httpd、syslogd等后台进程,分别拥有自己的运行账户mysql、apache和syslog;
  • Linux服务器程序通常是可配置的。服务器程序通常能处理很多命令行选项,如果一次运行的选项太多,则可以用配置文件来管理。绝大多数服务器程序都有配置文件,并存放在/etc目录下;
  • Linux服务器进程通常会在启动的时候生成一个PID文件并存入/var/run目录中,以记录该后台进程的PID;
  • Linux服务器程序通常需要考虑系统资源和限制,以预测自身能 承受多大负荷,比如进程可用文件描述符总数和内存总量等。

日志

服务器的调试和维护都需要一个专业的日志系统。Linux提供一个守护进程来处理系统日志——rsyslogd。rsyslogd守护进程既能接收用户进程输出的日志,又能接收内核日志。用户进程是通过调用syslog函数生成系统日志的。该函数将日志输出到一个UNIX本地域socket类型的文件/dev/log中, rsyslogd则监听该文件以获取用户进程的输出。rsyslogd守护进程在接收到用户进程或内核输入的日志后,会把它 们输出至某些特定的日志文件。默认情况下,调试信息会保存至var/log/debug文件,普通信息保存至/var/log/messages文件,内核消息则保存至/var/log/kern.log文件。

应用程序使用syslog函数与rsyslogd守护进程通信。syslog函数的定义如下:

#include<syslog.h>
void syslog(int priority,const char*message,...);

该函数采用可变参数来结构化输出,priority参数是所谓的设施值与日志级别的按位或,设施值的 默认值是LOG_USER,日志级别有如下几个:

#include<syslog.h>
#define LOG_EMERG 0/*系统不可用*/
#define LOG_ALERT 1/*报警,需要立即采取动作*/
#define LOG_CRIT 2/*非常严重的情况*/
#define LOG_ERR 3/*错误*/
#define LOG_WARNING 4/*警告*/
#define LOG_NOTICE 5/*通知*/
#define LOG_INFO 6/*信息*/
#define LOG_DEBUG 7/*调试*/

openlog可以改变syslog的默认输出方式:

#include<syslog.h>
void openlog(const char*ident,int logopt,int facility);

ident参数指定的字符串将被添加到日志消息的日期和时间之后,它通常被设置为程序的名字。logopt参数对后续syslog调用的行为进行配置。facility参数可用来修改syslog函数中的默认设施值。

日志的过滤也很重要。程序在开发阶段可能需要输出很多调试信息,而发布之后我们又需要将这些调试信息关闭。解决这个问题的方法并不是在程序发布之后删除调试代码(因为日后可能还需要用 到),而是简单地设置日志掩码,使日志级别大于日志掩码的日志信息被系统忽略。下面这个函数用于设置syslog的日志掩码:

#include<syslog.h>
int setlogmask(int maskpri);

maskpri参数指定日志掩码值。该函数始终会成功,它返回调用进程先前的日志掩码值。关闭日志功能:

#include<syslog.h>
void closelog();

用户信息

UID、EUID、GID和EGID

下面这一组函数可以获取和设置当前进程的真实用户ID(UID)、有效用户ID(EUID)、真实组ID(GID)和有效组ID(EGID):

#include<sys/types.h>
#include<unistd.h>
uid_t getuid();/*获取真实用户ID*/
uid_t geteuid();/*获取有效用户ID*/
gid_t getgid();/*获取真实组ID*/
gid_t getegid();/*获取有效组ID*/
int setuid(uid_t uid);/*设置真实用户ID*/
int seteuid(uid_t uid);/*设置有效用户ID*/
int setgid(gid_t gid);/*设置真实组ID*/
int setegid(gid_t gid);/*设置有效组ID*/

切换用户

下面的代码清单展示了如何将以root身份启动的进程切换为以一个普通用户身份运行:

static bool switch_to_user(uid_t user_id,gid_t gp_id)
{
    /*先确保目标用户不是root*/
if((user_id==0)&&(gp_id==0))
{
return false;
}
/*确保当前用户是合法用户:root或者目标用户*/
gid_t gid=getgid();
uid_t uid=getuid();
if(((gid!=0)||(uid!=0))&&((gid!=gp_id)||(uid!=user_id)))
{
return false;
}
/*如果不是root,则已经是目标用户*/
if(uid!=0)
{
return true;
}
/*切换到目标用户*/
if((setgid(gp_id)<0)||(setuid(user_id)<0))
{
return false;
}
return true;
}

进程间关系

进程组

Linux下每个进程都隶属于一个进程组,因此它们除了PID信息外,还有进程组ID(PGID)。我们可以用如下函数来获取指定进程的PGID:

#include<unistd.h>
pid_t getpgid(pid_t pid);

该函数成功时返回进程pid所属进程组的PGID,失败则返回-1并设置errno。每个进程组都有一个首领进程,其PGID和PID相同。进程组将一直存在,直到其中所有进程都退出,或者加入到其他进程组。设置PGID:

#include<unistd.h>
int setpgid(pid_t pid,pid_t pgid);

setpgid 函数成功时返回0,失败则返回-1并设置errno。一个进程只能设置自己或者其子进程的PGID。并且,当子进程调用exec系列函数后,我们也不能再在父进程中对它设置PGID。

会话

一些有关联的进程组将形成一个会话(session)。下面的函数用于创建一个会话:

#include<unistd.h>
pid_t setsid(void);

该函数不能由进程组的首领进程调用,否则将产生一个错误。对于非组首领的进程,调用该函数不仅创建新会话,而且有如下额外效果:

  • 调用进程成为会话的首领,此时该进程是新会话的唯一成员
  • 新建一个进程组,其PGID就是调用进程的PID,调用进程成为该组的首领。
  • 调用进程将甩开终端

该函数成功时返回新的进程组的PGID,失败则返回-1并设置errno。

用ps命令查看进程关系

执行ps命令可查看进程、进程组和会话之间的关系:

我们是在bash shell下执行ps和less命令的,所以ps和less命令的父进程是bash命令,这可以从PPID(父进程PID)一列看出。这3条命令创建 了1个会话(SID是2375)和2个进程组(PGID分别是2735和71265)。bash命令的PID、PGID和SID都相同,很明显它既是会话的首领,也是组2375的首领。ps命令则是组71256的首领,因为其PID也是71256;

 系统资源限制

 Linux上运行的程序都会受到资源限制的影响,比如物理设备限制 (CPU数量、内存数量等)、系统策略限制(CPU时间等),以及具体实现的限制(比如文件名的最大长度)。Linux系统资源限制可以通过如下一对函数来读取和设置:

#include<sys/resource.h>
int getrlimit(int resource,struct rlimit*rlim);
int setrlimit(int resource,const struct rlimit*rlim);

setrlimit和getrlimit成功时返回0,失败则返回-1并设置errno。rlim参数是rlimit结构体类型的指针,rlimit结构体的定义如下:

struct rlimit
{
    rlim_t rlim_cur;
    rlim_t rlim_max;
};

rlim_t是一个整数类型,它描述资源级别。rlim_cur成员指定资源的软限制,rlim_max成员指定资源的硬限制。软限制是一个建议性的、最好不要超越的限制,如果超越的话,系统可能向进程发送信号以终止其运行。例如,当进程CPU时间超过其软限制时,系统将向进程发送 SIGXCPU信号;当文件尺寸超过其软限制时,系统将向进程发送 SIGXFSZ信号。硬限制一般是软限制的上限。普通程序可以减小硬限制,而只有以root身份运行的程序才能增加硬限制。此外, 我们可以使用ulimit命令修改当前shell环境下的资源限制(软限制或/和硬限制),这种修改将对该shell启动的所有后续程序有效。我们也可以通过修改配置文件来改变系统软限制和硬限制,而且这种修改是永久。

resource参数指定资源限制类型。下列举了部分比较重要的资源限制类型:

 改变工作目录和根目录

有些服务器程序还需要改变工作目录和根目录,例如Web服务器,一般来说,Web服务器的逻辑根目录并非文件系统的根目录“/”,而是站点的根目录。

获取进程当前工作目录和改变进程工作目录的函数分别是:

#include<unistd.h>
char*getcwd(char*buf,size_t size);
int chdir(const char*path);

buf参数指向的内存用于存储进程当前工作目录的绝对路径名,其大小由size参数指定。如果当前工作目录的绝对路径的长度超过了size,则getcwd将返回NULL,并设置errno为 ERANGE。如果buf为NULL并且size非0,则getcwd可能在内部使用 malloc动态分配内存,并将进程的当前工作目录存储在其中。如果是这种情况,则我们必须自己来释放getcwd在内部创建的这块内存。getcwd 函数成功时返回一个指向目标存储区的指针,失败则返回NULL并设置errno。

chdir函数的path参数指定要切换到的目标目录。它成功时返回0, 失败时返回-1并设置errno。

改变进程根目录的函数是chroot,其定义如下:

#include<unistd.h>
int chroot(const char*path);

path参数指定要切换到的目标根目录。它成功时返回0,失败时返 回-1并设置errno。chroot并不改变进程的当前工作目录,所以调用chroot之后,我们仍然需要使用chdir(“/”)来将工作目录切换至新的根目录。只有特权进程才能改变根目录。

服务器程序后台化

如何在代码中让一个进程以守护进程的方式运行? 守护进程的编写遵循一定的步骤,下面代码将服务器程序以守护进程的方式运行:

bool daemonize()
{
    pid_t pid = fork();
    if ( pid < 0 )
        return false;
    else if ( pid > 0 )
        exit( 0 );

    umask( 0 );

    pid_t sid = setsid();
    if ( sid < 0 )
        return false;

    if ( ( chdir( "/" ) ) < 0 )
    {
        /* Log the failure */
        return false;
    }

    close( STDIN_FILENO );
    close( STDOUT_FILENO );
    close( STDERR_FILENO );

    open( "/dev/null", O_RDONLY );
    open( "/dev/null", O_RDWR );
    open( "/dev/null", O_RDWR );
    return true;
}

实际上,Linux提供了完成同样功能的库函数:

#include<unistd.h>
int daemon(int nochdir,int noclose);

其中,nochdir参数用于指定是否改变工作目录,如果给它传递0,则工作目录将被设置为“/”(根目录),否则继续使用当前工作目录。noclose参数为0时,标准输入、标准输出和标准错误输出都被重定向到/dev/null文件,否则依然使用原来的设备。该函数成功时返回0,失败则返回-1并设置errno。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android 11.0 系统设置显示主菜单添加屏幕旋转菜单实现旋转屏幕功能

1.前言 在android11.0的系统rom定制化开发中,在对系统设置进行定制开发中,有产品需求要求增加 旋转屏幕功能的菜单,就是在点击旋转屏幕菜单后弹窗显示旋转0度,旋转 90度,旋转180度, 旋转270度针对不同分辨率的无重力感应的大屏设备的屏幕旋转功能的实现, 接下来就来分析…

chatgpt赋能Python-python_dill

Python dill - 更高效&#xff0c;更强大的对象序列化工具 在Python编程中&#xff0c;对象序列化是一个非常常见的操作&#xff0c;它将Python对象转换为可以存储或传输的格式。Python默认提供了pickle模块来实现序列化&#xff0c;但是pickle存在一些限制&#xff0c;比如无…

usb摄像头驱动-core层usb设备的注册

usb摄像头驱动-core层driver.c 文章目录 usb摄像头驱动-core层driver.cusb_bus_typeusb_device_matchusb_uevent usb_register_driver 在ubuntu中接入罗技c920摄像头打印的信息如下&#xff1a; 在内核中&#xff0c;/driver/usb/core/driver.c 文件扮演了 USB 核心驱动程序管…

复现ms17-010漏洞

复现ms17-010 复现条件环境操作效果 让我们来看看“hkl”在干嘛 复现 条件 1.靶机必须为win8以下。 2.靶机必须同攻击机处于相同网段&#xff08;即倒数第二位相同&#xff09;。 3.靶机的445端口必须要开启。 环境 虚拟机kali为攻击机&#xff0c;win7虚拟机为靶机。 kali…

SELECT LAST_INSERT_ID()自增主键冲突或者为0问题

问题 数据库为mysql&#xff1b; mapper.xml文件为mybatis-generator自动生成的&#xff1b; 连接池使用DruidDataSource&#xff1b; 最终生成的insertSelective如下&#xff1a; 出现问题&#xff1a; 主键冲突&#xff1a;[WMyBatisTraceInterceptor:54][com.mysql.jdbc.…

如何定位OOM

造成OOM的原因 定位OOM 针对第一和第二种情况需要定位OOM 系统已经挂了&#xff1a; 通过堆dump文件定位。 当JVM发生OOM时&#xff0c;自动生成DUMP文件&#xff1a; -XX:HeapDumpOnOutOfMemoryError -XX:HeapDumpPath${目录} java -Xms10M -Xmx10M -XX:HeapDumpOnOutOfMemo…

c#中的json数据

JSON数据 数据传输的语言&#xff0c;用于前后端数据交互的语言&#xff0c;注意xml的区别。 json和xml的区别 xml&#xff1a;可扩展标记语言&#xff0c;是一种用于标记电子文件使其具有结构性的标记语言。 json&#xff1a;(JavaScript Object Notation, JS 对象简谱) 是…

昆仲被投企业「鲲游光电」近期完成新一轮数亿元融资,继续致力于探索前沿光电子领域产品与创新应用|昆仲·链

鲲游光电(North Ocean Photonics)是专注于晶圆级光学、光集成领域的高科技企业&#xff0c;总部位于中国上海。依托自身深厚的技术积累、高精度的制造工艺&#xff0c;鲲游光电通过融合集成光学与集成电路的创新思路&#xff0c;致力于探索前沿光子、光电子领域的实现与创新应用…

MyBatis环境搭建配置、增删改查操作、分页、事务操作、动态SQL、缓存机制、注解开发

MyBatis 文章目录 MyBatisXML语言简介用途各部分注解声明元素属性注释CDATA转义字符 搭建环境读取实体类创建实体与映射关系的文件 配置MyBatis创建工具类接口实现 Mybatis工作流程增删改查指定映射规则指定构造方法字段名称带下划线处理条件查询插入数据复杂查询和事务一对多查…

Codeforces Round 860 (Div. 2)

A Showstopper 题意&#xff1a;给你两个长度为n的数组a和b&#xff0c;每次操作你可以互换a[i]与b[i]&#xff0c;问最终能否满足 思路&#xff1a;若a[i]>b[i]&#xff0c;我们就进行操作。这样数组b元素都是较大的&#xff0c; 一定比不操作更优。最后判断是否满足条件…

Python中的异常处理机制

什么是异常与异常处理 异常就是错误 异常会导致程序崩溃并停止运行 能监控并捕获到异常&#xff0c;将异常部位的程序进行修理使得程序继续正常运行 异常的语法结构 try:<代码块1> 被try关键字检查并保护的业务代码except <异常的类型>:<代码块2> # 代码…

Mybatis源码细节探究:sqlSessionFactory.openSession()这个方法到底发生了什么?

给自己的每日一句 不从恶人的计谋&#xff0c;不站罪人的道路&#xff0c;不坐亵慢人的座位&#xff0c;惟喜爱耶和华的律法&#xff0c;昼夜思想&#xff0c;这人便为有福&#xff01;他要像一棵树栽在溪水旁&#xff0c;按时候结果子&#xff0c;叶子也不枯干。凡他所做的尽…

【笔记】【Javascript】浅面了解原型和原型链

前言 原型和原型链是学习前端必备知识笔记中有些个人理解后整理的笔记&#xff0c;可能有所偏差&#xff0c;也恳请读者帮忙指出&#xff0c;谢谢。 免责声明 为了方便&#xff0c;本文中使用的部分图片来自于网络&#xff0c;如有侵权,请联系博主进行删除&#xff0c;感谢其…

C++ 二分查找法 LeetCode:704. 二分查找

class Solution { public:int search(vector<int>& nums, int target) {int length nums.size();//计算容器长度int left 0;//0int right length-1;//5int middle 0;/*while(left<right){middle (leftright)/2;//middle (leftright)>>1;if(nums[middl…

mysql子查询嵌套

目录 前言 一、实际需求解决 1.方式1&#xff1a;自连接 2.方式2&#xff1a;子查询 二、单行子查询 1.操作符子查询 三、相关子查询 四、自定义语句 五、子查询的问题 1.空值问题 2.非法使用子查询 六、多行子查询 七、聚合函数的嵌套使用 八、多行子查询空值问题…

Python爬虫实战——获取指定博主所有专栏链接及博文链接

Python爬虫实战——获取指定博主所有专栏链接及博文链接 0. 前言1. 第三方库的安装2. 代码3. 演示效果 0. 前言 本节学习使用爬虫来爬取指定csdn用户的所有专栏下的文章 操作系统&#xff1a;Windows10 专业版 开发环境&#xff1a;Pycahrm Comunity 2022.3 Python解释器版…

带你学C带你飞-P16拾遗

自增运算符 #include <stdio.h> int main() {int i5,j;j i;printf("i%d,j%d",i,j);i5;ji;printf("i%d,j%d",i,j); }i:先使用i的值&#xff0c;再对i自身进行加一 i&#xff1a;先对i自身加一&#xff0c;再赋值给j 逗号运算符 条件运算符 三目运…

【Linux】冯诺依曼体系结构、操作系统概念、进程概念

文章目录 前言一、冯诺依曼体系结构1.简介冯诺依曼体系2.CPU3.存储器3.IO&#xff08;输入输出&#xff09;4.总结 二、操作系统&#xff08;OS&#xff09;1.操作系统是什么&#xff1f;2.为什么有操作系统&#xff1f;&#xff08;功能&#xff09;3.操作系统如何实现功能&am…

MySQL之触发器相关操作

1. 概念 触发器&#xff0c;就是⼀种特殊的存储过程。触发器和存储过程⼀样是⼀个能够完成特定功能、存储 在数据库服务器上的SQL⽚段&#xff0c;但是触发器⽆需调⽤&#xff0c;当对数据表中的数据执⾏DML操作时 ⾃动触发这个SQL⽚段的执⾏&#xff0c;⽆需⼿动调⽤。 在MyS…

前端食堂技术周刊第 83 期:TS 5.1 RC、Nuxt 3.5、INP、Kinp、管理 GitHub 通知、WebXR

By Midjournery 美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;杏花乌龙拿铁 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 本期摘要 TypeScript 5.1 RCNuxt 3.5INP 将成为新的 Core Web…