Linux 服务器程序规范、服务器日志、用户、进程间的关系

文章目录

  • 服务器程序规范
  • 日志
    • rsyslogd 守护进程
    • syslog函数
    • openlog函数
    • setlogmask函数
    • closelog函数
  • 用户
  • 进程间的关系
    • 进程组
    • 会话
    • 系统资源限制
    • 改变工作目录和根目录
    • 服务器程序后台化


服务器程序规范

  1. Linux 服务器程序一般以后台进程(守护进程[daemon])形式运行。它没有控制终端,因此不会意外接受到用户输入,守护进程的父进程通常是 init 进程(PID为1)。
  2. 服务器的调试和维护都需要一个专业的日志系统,Linux 常用一个守护进程 rsyslogd(syslogd的升级版) 来处理系统日志。
  3. Linux 服务器程序一般以 非root 的身份运行。如:mysqldhttpdsyslogd 等后台进程分别拥有自己的运行账户 mysqlapachesyslog
  4. Linux 服务器程序通常能处理很多命令行选项,如果一次运行的选项太多,那么可以用配置文件来管理。配置文件一般放在 /etc 目录下。
  5. Linux 服务器程序通常在启动时会生成一个记录该后台进程 PID 的文件并存入 /var/run 目录中。例如: syslogdPID 文件是 /var/run/syslogd.pid

日志

rsyslogd 守护进程

既能接受用户进程输出的日志,也能接受内核日志。

  • 用户进程调用 syslog函数 将日志输出到一个 UNIX 本地域 socket 类型(AF_UNIX)的文件 /dev/log 中,rsyslogd 则监听该文件以获得用户进程的输出。
  • 内核日志由 printk 等函数打印至内核的 环状缓存(ring buffer) 中,环状缓存的内容直接映射到 /proc/kmsg 中,rsyslogd 读取该文件以获得内核日志。

在这里插入图片描述


syslog函数

应用程序通过 syslog函数rsyslogd 守护进程通信:

#include<syslog.h>
void syslog( int priority, const char* message, ...);
// 采用可变参数(message 和 第三个参数……)来结构化输出
// priority:设施值与日志级别的按位或,设施值的默认值是 LOG_USER。

限于 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 调用的行为进行配置,为下列值的按位或:
#define LOG_PID     0x01 // 在日志消息中博阿寒程序 PID
#define LOG_CONS    0x02 // 如果消息不能记录到日志文件,则打印至终端
#define LOG_ODELAY  0X04 // 延迟打开日志功能知道第一次调用 syslog
#define LOG_NDELAY  0x08 // 不延迟打开日志功能
// facility用来修改 syslog 函数中的默认设施值

setlogmask函数

程序在开发阶段可能需要输出很多调试信息,而发布之后又需要将这些调试信息关闭。

解决这个问题的方法并非是在发布后删除调试代码(日后可能还需要用到),而有更简单的做法——设置日志掩码,使日志级别大于掩码日志信息被系统忽略。

setlogmask函数 就用以设置日志掩码:

#include<syslog.h>
int setlogmask( int maskpri );
// maskpri指定日志掩码值
// 该函数始终会成功,返回调用进程旧的日志掩码值

closelog函数

用以关闭日志功能:

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

用户

服务器中不同的用户有不同的权限,因此 获取or设置 当前进程的 真实用户ID(UID)、有效用户ID(EUID)、真实组ID(GID)、有效组(EGID) 就尤为重要:

#include <sys/types.h>
#include <unistd.h>
uid_t getuid();
uid_t geteuid();
gid_t getgid();
gid_t getegid();
int setuid( uid_t uid );
int seteuid( uid_t uid );
int setgid( gid_t gid );
int setegid( gid_t gid );

一个进程有两个 用户ID: UIDEUIDEUID 方便了资源访问:使得 运行程序的用户 拥有 该程序的有效用户 的权限。如:任何用户都可以通过 su程序 修改自己的账户信息,这就不得不访问需要 root 权限的 /etc/passwd 文件。那么以普通用户身份启动的 su程序 如何能访问/etc/passwd 文件呢?

ls 命令可以查看到,su程序 的所有者是 root,且被设置了 set-user-id标志 ,即任何普通用户运行 su程序 时,su程序 的有效用户为 root。有效用户为 root 的进程被称为 特权进程(privileged processes)

类似的,EGID 为运行目标程序的组用户提供有效组的权限。


进程间的关系

进程组

Linux 下每个进程都隶属于一个进程组,PGID 即为它的 进程组ID。进程组将一直存在,知道其中所有进程都退出或者加入到其他线程组。每个进程组都有一个首领进程,其 PGIDPID 相同。

#include< unistd.h>
pid_t getpgid( pid_t pid );
// 成功返回 ID,失败返回 -1 并设置 errno
int setpgid( pid_t pid, pid_t pgid );
// 将 PID 为 pid 的进程的 PGID 设置为 pgid,若 pid 和 pgid 相等,则 pid 指定的进程将被设定为进程组首领
// 若 pid=0,则表示设置 当前进程 的 PGID 为 pgid
// 若 pgid=0,则使用 pid 作为目标进程的 PGID 
// 成功时返回 0,失败返回 -1 并设置 errno

一个进程只能设置自己或者子进程的 PGID,子进程调用 exec 系列函数后,父进程不再能设置它的 PGID


会话

一些有关联的进程组能形成一个会话session),下面的函数用以创建一个会话:

#include<unistd.h>
pid_t setsid( void );
// 成功时返回新的进程组的 PGID,失败则返回 -1 并设置 errno

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

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

Linux 进程并未提供所谓 会话ID(SID) 的概念,但将会话首领所在的进程组的 PGID 视为 SID,并提供了如下函数来读取 SID

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

系统资源限制

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

#include <sys/resource.h>
int getrlimit( int resource, struct rlimit* rlim );
int setrlimit( int resource, const struct rlimit* rlim );
// 成功时返回 0,失败时返回 -1 并设置 errno。
struct rlimit{rlim_t rlim_cur; // 指定资源的软限制,是一个建议性的,最好不要超越的限制,若超越限制,则系统可能向进程发送信号以终止其运行。rlim_t rlim_max; // 指定资源的硬限制,一般是软限制的上限。普通程序可以减小硬限制,只有以 root 身份运行的程序才能增加硬限制。// rlim_t是一个整数类型,描述资源级别。
};

除上述外:

  • 还可以使用 ulimit 命令修改当前 shell 环境下的资源限制(软限制或/和硬限制),这种修改将对该 shell 启动的所有后续程序有效。
  • 还可以通过修改配置文件来改变系统软限制和硬限制,这种修改是永久的。

改变工作目录和根目录

#include<unistd.h>
/* 获取进程当前工作目录 */
char* getcwd( char* buf, size_t size );
// buf指向的内存用于存储进程当前工作目录的绝对路径名,大小由 size 参数指定
// 如果当前工作的绝对路径长度(加上末尾的“\0”)超过了 size,则返回 NULL 并设置 errno 为 ERANGE。
// 若 buf 为 NULL 并且 size 非 0,则 getcwd 可能在内部使用 malloc 动态分配内存,并将进程的当前工作目录存储在其中,
// 此时我们需要自己释放 getcwd 在内部创建的这块内存。
// 成功返回一个指向目标存储区(buf指向的缓存区或者getcwd在内部动态创建的缓存区)的指针,失败返回 NULL 并设置 errno。/* 改变进程的工作目录 */
int chdir( const char* path );
// path 指定要切换到的目标目录
// 成功返回 0,失败返回 -1 并设置 errno/* 改变进程根目录 */
int chroot(const char* path);
// 参数和返回值同上,调用本函数后,仍需使用 chdir("/") 来将工作目录切换至新的根目录。
// 改变进程的根目录后,程序可能无法访问处于旧路径的文件or目录,
// 不过可以利用进程已经打开的文件描述符来访问调用 chroot 之后不能直接访问的文件。
// 只有特权进程才能改变根目录

服务器程序后台化

让一个进程以守护进程的方式运行:

#include<unistd.h>
int daemon(int nochdir, int noclose);
// nochdir 用于指定是否改变工作目录,为 0 则工作目录被设置为“/”(根目录),否则继续使用当前目录
// noclose 为 0 时,标准输入、输出、错误输出都被重定向到 /dev/null 文件,否则依然使用原来的设备
// 成功返回 0,失败返回 -1 并设置 errno

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

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

相关文章

IO模型 :阻塞IO、非阻塞IO、信号驱动IO、异步IO、多路复用IO

文章目录IO模型阻塞IO非阻塞IO信号驱动IO多路复用IO异步IOIO模型 根据各自的特性不同&#xff0c;IO模型被分为阻塞IO、非阻塞IO、信号驱动IO、异步IO、多路复用IO五类。 最主要的两个区别就是阻塞与非阻塞&#xff0c;同步与异步。 阻塞与非阻塞 阻塞与非阻塞最主要的区别就…

Tomcat服务器集群与负载均衡实现

一、前言 在单一的服务器上执行WEB应用程序有一些重大的问题&#xff0c;当网站成功建成并开始接受大量请求时&#xff0c;单一服务器终究无法满足需要处理的负荷量&#xff0c;所以就有点显得有点力不从心了。另外一个常见的问题是会产生单点故障&#xff0c;如果该服务器坏掉…

Linux服务器 | 事件处理模式:Reactor模式、Proactor模式

文章目录Reactor模式Proactor模式同步I/O模型模拟Proactor模式两者的优缺点ReactorProactor同步I/O模型通常用于实现 Reactor 模式&#xff0c;异步I/O模型通常用于实现 Proactor 模式。&#xff08;不是绝对的&#xff0c;同步I/O也可模拟出 Proactor 模式&#xff09; React…

Linux服务器 | 服务器模型与三个模块、两种并发模式:半同步/半异步、领导者/追随者

文章目录两种服务器模型及三个模块C/S模型P2P模型I/O处理单元、逻辑单元、存储单元并发同步与异步半同步/半异步模式变体&#xff1a;半同步/半反应堆模式改进&#xff1a;高效的半同步/半异步模式领导者/追随者模式组件 &#xff1a;句柄集、线程集、事件处理器工作流程两种服…

字符串匹配之KMP(KnuthMorrisPratt)算法(图解)

文章目录最长相等前后缀next数组概念代码实现图解GetNext中的回溯改进代码实现代码复杂度分析最长相等前后缀 给出一个字符串 ababa 前缀集合&#xff1a;{a, ab, aba, abab} 后缀集合&#xff1a;{a, ba, aba, baba} 相等前后缀 即上面用同样颜色标识出来的集合元素&#…

Android入门(一) | Android Studio的配置与使用

文章目录安装配置Android Studio使用Android Studio模拟器更改Android SDK的路径Hello World&#xff01;安装配置Android Studio 从这一步开始&#xff1a; 一直点 next 即可&#xff0c;直到存储路径的选择上&#xff0c;可以放到非 C 盘&#xff0c;这里我放到 D 盘了&am…

Android 入门(四) | Intent 实现 Activity 切换

文章目录Intent显式 Intent定义两个 xml 文件android:orientationmatch_parent 和 wrap_contentIntent函数定义两个 Activity隐式 Intent更多隐式 Intent 的用法用隐式 Intent 打开系统浏览器自建 Activity 以响应打开网页的 Intent向下一个活动传递数据返回数据给上一个活动In…

Android入门(二) | 项目目录及主要文件作用分析

文章目录项目目录分析app目录分析AndroidManifest.xml 分析MainActivity.kt 分析build.gradle 分析最外层目录下的 build.gradleapp 目录下的 build.gradle项目目录分析 我们来看一下 src/main/res 下的一些文件&#xff1a; .gradle 和 .idea &#xff1a;这两个目录下放置…

Android入门(三) | Android 的日志工具 Logcat

文章目录日志工具类 android.util.LogLogcat 中的过滤器日志工具类 android.util.Log Log 从属日志工具类 android.util.Log &#xff0c;该类提供了五个方法供我们打印日志&#xff1a; Log.v() &#xff1a;用于打印那些最为琐碎的、意义最小的日志信息。对应级别 verbose&…

Android入门(五) | Activity 的生命周期

文章目录Activity 的状态及生命周期实现管理生命周期FirstActivitySecondActivityDialogActivity运行结果旧活动被回收了还能返回吗&#xff1f;Activity 的状态及生命周期 Android 的应用程序运用 栈&#xff08;Back Stack&#xff09; 的思想来管理 Activity&#xff1a; …

Android入门(六) | Activity 的启动模式 及 生产环境中关于 Activity 的小技巧

文章目录Activity 的启动模式standardsingleTopsingleTasksingleInstance技巧了解当前界面是哪个 Activity随时随地退出程序启动活动的最佳写法Activity 的启动模式 standard&#xff1a;默认的启动方式&#xff0c;每次启动一个活动都会重新创建singleTop&#xff1a;如果该活…

Android入门(七) | 常用控件

文章目录TextView 控件&#xff1a;文本信息Button 控件&#xff1a;按钮EditText 控件&#xff1a;输入框ImageView 控件&#xff1a;图片ProgressBar 控件&#xff1a;进度条AlertDialog 控件&#xff1a;提示框ProgressDialog 控件&#xff1a;带有进度条的提示框TextView 控…

Android入门(八) | 常用的界面布局 及 自定义控件

文章目录LinearLayout &#xff1a;线性布局android:layout_gravity &#xff1a;控件的对齐方式android:layout_weight&#xff1a;权重RelativeLayout &#xff1a;相对布局相对于父布局进行定位相对于控件进行定位边缘对齐FrameLayout &#xff1a;帧布局Percent &#xff1…

Android入门(九)| 滚动控件 ListView 与 RecyclerView

文章目录ListView内置类型的简单运用定制数据类型提升效率点击事件RecyclerView布局管理器点击事件ListView 内置类型的简单运用 由于手机屏幕空间有限&#xff0c;能够一次性在屏幕上显示的内容不多&#xff0c;当我们的程序有大量数据需要显示的时候就可以借助 ListView 来…

Android入门(10)| Fragment碎片详解

文章目录为什么要使用碎片&#xff08;Fragment&#xff09;实例布局文件FragmentActivity动态添加碎片布局文件FragmentActivity碎片通信Fragment布局文件Activity生命周期为什么要使用碎片&#xff08;Fragment&#xff09; 我们在手机上看新闻可能是这样的&#xff1a; Re…

Android开发(1) | Fragment 的应用——新闻应用

文章目录Item&#xff1a;标题子项布局文件Java代码标题碎片布局文件Java代码新闻内容碎片布局文件Java代码新闻内容活动布局文件Java代码首界面布局文件Java代码Item&#xff1a;标题子项 布局文件 news_item.xml&#xff1a; <TextViewxmlns:android"http://schema…

Android入门(11)| 全局广播与本地广播

文章目录广播概念接收广播动态注册实例静态注册实例发送广播发送标准广播广播的跨进程特性发送有序广播本地广播广播概念 Android 中的每个应用程序都可以对自己感兴趣的广播进行注册&#xff0c;这样该程序就只会接收到自己所关心的广播内容&#xff0c;这些广播可能是来自系…

Android开发(2) | 广播 Broadcast 的应用——强制下线功能

文章目录功能简介关闭所有活动登陆界面发送强制下线的广播广播接收器AndroidManifest.xml运行结果功能简介 强制下线功能只需要弹出一个对话框&#xff0c;让用户只能点击确定按钮&#xff0c;回到登录界面。 如果在每一个活动中添加一个对话框的话太过繁琐&#xff0c;用广播…

Android入门(12)| 数据持久化

文章目录数据持久化文件存储将数据存储进文件实例从文件中读取数据实例SharedPreferences存储将数据存储进文件实例从文件中读取数据实例实现记住密码的功能SQLite数据库存储创建自己的帮助类调用自己的帮助类补全 onUpgrade() 方法增删查改增&#xff1a;SQLiteDatabase.inser…

Android入门(13)| Android权限 与 内容提供器

文章目录普通权限与危险权限运行时申请权限内容提供器运用安卓封装好的内容提供器自实现的内容提供器概念实现普通权限与危险权限 主要用于不同应用程序之间在保证被访数据的安全性的基础上&#xff0c;实现数据共享的功能。 在 Android 6.0 开始引入了运行时权限的功能&…