《UNIX环境高级编程》笔记 第十三章-守护进程

2023-11-12

1. 概念

守护进程(daemon)是生存期长的一种进程。它们常常在系统引导装入时启动,仅在系统关闭时才终止。因为它们没有控制终端,所以说它们是在后台运行的

Linux的大多数服务就是用守护进程实现的。这些守护进程名通常以d结尾,如inetd提供网络服务,sshd提供ssh登录服务,httpd提供web服务等待。

  • 大多数守护进程都以超级用户权限运行

  • 所有守护进程都没有控制终端。用户层守护进程缺少控制终端可能是守护进程调用了setsid的结果(setsid会断开与控制终端的联系)。

  • 大多数用户层守护进程都是进程组的组长进程以及会话的首进程,而且是这些进程组和会话中的唯一进程

  • 用户层进程的父进程是init(1)进程。

2. 守护进程编程规则

编写守护进程程序时需要遵循一些基本规则,以防止产生不必要的交互作用。

  • 调用umask将文件模式创建屏蔽字设置为一个已知值(通常是0)。由继承(如fork)得来的文件模式创建屏蔽字可能会被设置为拒绝某些权限。如果守护进程要创建文件,那么它可能要设置特定的权限。

  • 调用fork,然后使父进程exit退出,这样会实现以下几点:

    • 如果该守护进程是shell命令启动的,那么父进程终止会让shell认为这条命令已经执行完毕
    • 虽然子进程继承了父进程的进程组ID,但是获得了一个新的进程ID,因此子进程不是该进程组的组长进程,这是接下来进行setsid调用的先决条件
  • 调用setsid创建一个新会话,这样会使调用进程:

    • 成为新会话的首进程
    • 成为新进程组的组长进程
    • 没有控制终端

    有些建议此时再次调用fork,终止父进程,继续使用子进程中的守护进程,这就保证了该守护进程不是会话首进程,可以防止它取得控制终端。

    为了避免取得控制终端的另一种方法是:当用open函数打开终端设备时,设置O_NOCTTY标志

  • 将当前工作目录更改为根目录

    从父进程处继承过来的当前工作目录可能在一个挂载的文件系统处。因为是守护进程通常在系统再引导前一直存在,所以如果守护进程的当前工作目录在一个挂载文件系统中,那么该文件系统就不能被卸载。

  • 关闭不再需要的文件描述符。这使得守护进程不再持有从其父进程继承来的任何文件描述符:可以通过getrlimit函数判定最高文件描述符值,并关闭直到该值的所有描述符。

  • 某些守护进程打开/dev/null使文件描述符0/1/2指向该文件。这样使得任何一个试图读标准输入、写标准输出或标准错误的例程都不会产生任何效果。因为守护进程不与终端设备关联,因此其输出无处显式,也无处从交互式用户那里接收输入。

    /dev/null文件:

    一个字符设备文件。称为空设备,它丢弃一切写入其中的数据(但报告写入操作成功),读取它则会立即得到一个EOF。

    /dev/null 被称为位桶(bit bucket)或者黑洞(black hole)。空设备通常被用于丢弃不需要的输出流,或作为用于输入流的空文件。这些操作通常由重定向完成。

    /dev/zero文件:

    一个字符设备文件。当你读它的时候,它会提供无限的空字符(NULL, 即0x00)。写入/dev/zero的内容会丢失不见。

    /dev/random和/dev/urandom文件:

    字符设备文件。随机数设备,提供不间断的随机字节流。二者的区别是/dev/random产生随机数据依赖系统中断,当系统中断不足时,/dev/random设备会“挂起”,因而产生数据速度较慢,但随机性好;/dev/urandom不依赖系统中断,数据产生速度快,但随机性较低。

**示例程序,初始化一个守护进程:**其中关于出错记录部分函数在下一节讲解

void daemonize(const char * cmd) {
    //清空文件模式创建屏蔽字
    umask(0);

    //获取最大文件描述符
    struct rlimit rl;
    if(getrlimit(RLIMIT_NOFILE,&rl) < 0) {
        perror("无法获取最大文件描述符");
    }

    //成为会话首进程并失去控制终端
    pid_t pid;
    if(fork() != 0) { // 父进程
        exit(0);
    }
    setsid();

    //确保该守护进程不会有控制终端
    struct sigaction sa;
    sa.sa_handler = SIG_IGN;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGHUP,&sa,NULL); // 忽略SIGHUP信号
    if(fork() != 0) {
        exit(0);
    }

    //更改工作目录为根目录
    chdir("/");

    //更改所有打开的文件描述符
    if(rl.rlim_max == RLIM_INFINITY)
        rl.rlim_max = 1024;
    for(int i = 0 ; i < rl.rlim_max ; ++i) {
        close(i);
    }

    //将文件描述符0/1/2指向/dev/null
    int fd0 = open("/dev/null",O_RDWR);
    int fd1 = dup(0);
    int fd2 = dup(0);

    //初始化log文件
    openlog(cmd,LOG_CONS,LOG_DAEMON);
    if(fd0 != 0 || fd1 != 1 || fd2 !=2) {
        syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2);
        exit(1);
    }
}

3. 出错记录

3.1 syslog设施

因为守护进程不应该有控制终端,所以不能只是将出错消息写到标准错误上。我们不希望所有守护进程都写到控制台设备上,也不希望每个守护进程将它自己的出错消息写到一个单独的文件中。

因此需要关心哪一个守护进程写到哪一个记录文件中,可以通过一个集中的守护进程出错记录设施来进行这种管理操作

大多数守护进程使用syslog设施,其组织结构如下

在这里插入图片描述

有以下3种产生日志消息的方法:

  • 内核例程调用log函数向产生日志消息
  • 大多数用户守护进程调用syslog函数产生日志消息,该函数将消息发送至UNIX域数据报套接字/dev/log。/dev/log是一个套接字类型文件
  • 无论一个用户进程在此主机上,还是在通过TCP/IP网络连接到此主机的其他主机上,都可以将日志消息发送到UDP端口514

其中syslogd是一个守护进程。不同的进程(client)都可以将log 输送给syslogd(server),由syslogd 集中收集。syslogd可以将log保存到本地,也可以发送到共享内存或远程服务器

syslogd守护进程读取所有3种格式的日志消息。syslogd在启动时读一个配置文件/etc/syslog.conf,该文件决定了不同种类消息应该送往何处。如一个紧急消息可在控制台上打印,而警告信息记录到一个文件中。

3.1 syslog设施的接口函数

void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void);
int setlogmask(int mask);

调用openlog是可选择的。如果不调用openlog,则在第一次调用syslog时,自动调用openlog。

closelog也是可选的,因为它只是关闭曾被用于与syslogd守护进程进行通信的描述符

openlog函数:

  • ident参数:此参数是一个字符串,将被加至每一则日志消息中。(类比perror函数)

  • option参数:指定的标志用来控制openlog()操作和syslog()的后续调用。他的值为下列值或运算的结果

    • LOG_CONS:若日志消息不能通过UNIX域数据报套接字送至syslogd守护进程,则将该消息写至控制台
    • LOG_NDELAY:立即打开至syslogd守护进程的UNIX域数据包套接字,不要等到第一条消息已经被记录时再打开。(通常在记录第一条消息前不打开该套接字文件)
    • LOG_NOWAIT:在记录日志信息时,不等待可能的子进程的创建
    • LOG_ODELAY:在第一条消息被记录之前延迟打开至syslogd守护进程的连接
    • LOG_PERROR:除了将日志消息发送给syslogd以外,还将它写至标准错误stderr
    • LOG_PID:每条消息都包含进程PID
  • facility参数:指定记录消息程序的类型。syslogd通过指定的配置文件,将以不同的方式来处理来自不同设施的消息(即这个要与syslogd守护进程的配置文件对应,日志信息会写入syslog.conf文件的指定位置)。

    如果不调用openlog或者该参数值为0,则在调用syslog时,可以将facility参数作为syslog的priority参数的一部分。

在这里插入图片描述

syslog函数:产生一个日志消息

  • priority参数:其priority参数是facility和level的组合

在这里插入图片描述

  • format参数:其中%m字符被替换成errno值对应的出错消息字符串(strerror)

例如,在一个行式打印机假脱机守护进程中,可能有下列调用序列

openlog("lpd",LOG_PID,LOG_LPR);
syslog(LOG_ERR,"open error for %s:%m",filename);

若不调用openlog,则可能会是以下形式

syslog(LOG_LPR|LOG_ERR,"open error for %s:%m",filename);

setlogmask函数:设置进程的记录优先级屏蔽字,并返回之前的屏蔽字

  • mask参数:日志优先级掩码,在该掩码中的消息才会被真正记录。该掩码是level中各个常量的按位或

4. 单实例守护进程

有时候需要在任意时刻只运行该守护进程的一个副本。如果同时运行该守护进程的多个实例,则会出现错误。

可以通过文件和记录锁机制,该方法保证一个守护进程只有一个副本在运行。如果每一个守护进程创建一个有固定名字的文件,并在该文件的整体上加一个写锁,那么只允许创建一把这样的写锁。再此之后创建写锁的尝试都会失败,这向后续守护进程副本指明已有一个副本正在运行。

文件和记录锁提供了一种方便的互斥机制。如果守护进程在一个文件的整体上得到一把写锁,那么在该是守护进程终止时,这把锁将被自动删除。这就简化了复原所需的操作。

以下程序说明了如何使用文件和记录锁来保证只运行守护进程的一个副本

#define LOCKFILE "/var/run/daemon.pid"
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
extern int lockfile(int);
int already_running(void) {
    int fd = open(LOCKFILE,O_RDWR|O_CREAT,LOCKMODE);
    if(fd < 0) {
        syslog(LOG_ERR,"cannot open %s:%m",LOCKFILE);
        exit(1);
    }
    if(lockfile(fd) < 0) {
        if(errno == EACCES || errno == EAGAIN) {
            //守护进程实例已经存在
            close(fd);
            return 1;
        }
        syslog(LOG_ERR,"cannot lock %s:%m",LOCKFILE);
        exit(1);
    }
    //说明该进程是守护进程的唯一副本
    ftruncate(fd,0);
    char buf[16];
    sprintf(buf,"%ld",(long)getpid());
    write(fd,buf,strlen(buf)+1);
    return 0;
}

该函数会使得守护进程将自己PID写入到指定文件中。如果该文件已经加了锁,那么lockfile函数将会返回失败,errno设为EACCES或EAGAIN(lockfile函数的具体实现见下一章)

5. 守护进程的惯例

  • 若守护进程使用锁文件,那么该文件通常存储在/var/run目录中(/var 包括系统运行时要改变的数据)。守护进程可能需要超级用户权限才能在此目录下创建文件。锁文件的名字通常是name.pid,其中name是该守护进程或服务的名字。如cron守护进程锁文件的名字就是/var/run/crond.pid

  • 若守护进程支持配置选项,那么配置文件通常存放在/etc目录中。配置文件的名字通常是name.conf,其中name是该守护进程或服务的名字。例如syslogd守护进程的配置文件通常是/etc/syslog.conf

  • 守护进程可用命令行启动,但通常它们是由系统初始化脚本之一(/etc/rc*或/etc/init.d/*)启动的。如果在守护进程终止时,应当自动地重新启动它,则我们可以在/etc/inittab中为该守护进程包括respawn记录项,这样init就重新启动该守护进程。

  • 若一个守护进程有一个配置文件,那么当该守护进程启动时会读该文件,但在之后一般就不会再查看它。若某个管理员更改了配置文件,那么该守护进程可能需要被停止,然后再启动,以使配置文件生效。

    为避免这种麻烦,某些守护进程将捕捉SIGHUP信号,当它们收到该信号时重新读配置文件

    • 比如通过设置SIGHUP的信号捕捉函数,当收到SIGHUP时在信号捕捉函数内进行配置文件重读;

    • 或者在一个专用线程内通过sigwait函数同步的等待SIGHUP信号阻塞,当有阻塞的SIGHUP时,sigwait函数返回,然后执行配置文件重读。

6. 客户进程-服务器进程模型

守护进程通常被用作服务器进程

例如syslogd进程就是服务器进程,而用户进程(客户进程)用UNIX域数据报套接字向其发送消息。syslogd服务器进程提供的服务就是将一条出错消息记录到日志文件中。

7. 补充:ls -l命令第一列结果

在这里插入图片描述

8. 补充:inittab文件

转自https://www.cnblogs.com/uestc-mm/p/11985696.html

Linux在完成核内引导(内核镜像已被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,接着通过启动一个用户级程序init来启动其他用户级的进程或服务

init程序需要读取配置文件/etc/inittab来作为进程运行的参数。inittab是一个不可执行的文本文件,它有若干行指令所组成。

/etc/inittab文件中每个登记项的结构都是一样的,共分为以冒号:分隔的4个字段.具体如下:

<id>:<runlevels>:<action>:<process>

其中,各字段以及与其相关的说明如下:

id: 登记项标识符,最多为4个字符.用于唯一地标识/etc/inittab文件中的每一个登记项。

**run_level:**系统运行级,即执行登记项的init级别。用于指定相应的登记项适用于哪一个运行级,即在哪一个运行级中被处理。如果该字段为空,那么相应的登记项将适用于所有的运行级。在该字段中,可以同时指定一个或多个运行级:

Linux有7个运行级别,如下:

  • 0:关机。
  • 1:单用户字符界面。
  • 2:不具备网络文件系统(NFS)功能的多用户字符界面。
  • 3:具有网络功能的多用户字符界面。
  • 4: 保留不用。
  • 5:具有网络功能的图形用户界面。
  • 6:重新启动系统。

action: 动作关键字。用于指定init命令或进程对相应进程(在“process”字段定义)所实施的动作。具体动作包括:

  • ***boot:***只有在引导过程中,才执行该进程,但不等待该进程的结束;当该进程死亡时,也不重新启动该进程.
  • ***bootwait:***只有在引导过程中,才执行该进程,并等待进程的结束:当该进程死亡时,也不重新启动该进程.实际上,只有在系统被引导后,并从单用户方式进入多用户方式时,这些登记项才被处理;如果系统的默认运行级设置为2(即多用户方式),那么这些登记项在系统引导后将马上被处理.
  • ***initdefault:***指定系统的默认运行级.系统启动时,init将首先查找该登记项.如果存在init将据此决定系统最初要进入的运行级.具体来说,init将指定登记项“run_level"字段中的最大数字(即最高运行级)为当前系统的默认运行级;如果该字段为空,那么将其解释为“0123456”,并以“6”作为默认运行级.如果不存在该登记项,那么init将要求用户在系统启动时指定一个最初的运行级.
  • ***off:***如果相应的进程正在运行,那么就发出一个警告信号,等待20秒后,再通过杀死信号强行终止该进程.如果相应的进程并不存在那么就忽略该登记项.
  • ***once:***启动相应的进程,但不等待该进程结束便继续处理/etc/inittab文件中的下一个登记项;当该进程死亡时,init也不重新启动该进程.注意:在从一个运行级进入另一个运行级时,如果相应的进程仍然在运行,那么init就不重新启动该进程.
  • ***ondemand:***与“respawn”的功能完全相同,但只用于运行级为a、b或c的登记项.
  • ***powerfail:***只在init接收到电源失败信号时执行相应的进程,但不等待该进程结束.
  • ***powerwait:***只在init接收到电源失败信号时执行相应的进程,并在继续对/etc/inittab文件进行任何处理前等待该进程结束.
  • ***respawn:***如果相应的进程还不存在,那么init就启动该进程,同时不等待该进程的结束就继续扫描/etc/inittab文件;当该进程死亡时,init将重新启动该进程.如果相应的进程已经存在,那么init将忽略该登记项并继续扫描/etc/inittab文件.
  • ***sysinit:***只有在启动或重新启动系统并首先进入单用户时,init才执行这些登记项.而在系统从运行级1-6进入单用户方式时,init并不执行这些登记项."action”字段为“sysinit”的登记项在“run_level”字段不指定任何运行级.
  • ***wait:***启动进程并等待其结束,然后再处理/etc/inittab文件中的下一个登记项.

process: 所要执行的shell命令.任何合法的shell语法均适用于该字段.

9. daemon函数

用于将调用进程(其实是daemon函数中fork的子进程)变为守护进程,脱离控制台,在后台运行

int daemon(int nochdir, int noclose);
  • 当 nochdir为零时,当前目录变为根目录,否则不变;

  • 当 noclose为零时,标准输入、标准输出和错误输出重定向为/dev/null,也就是不输出任何信 息,否则照样输出。

其大致实现类似于前文的daemonize函数,父进程在fork后终止,子进程在daemon函数返回后成为守护进程,继续执行后面的指令。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《UNIX环境高级编程》笔记 第十三章-守护进程 的相关文章

  • jq中如何分组?

    这是 json 文档 name bucket1 clusterName cluster1 name bucket2 clusterName cluster1 name bucket3 clusterName cluster2 name bu
  • 查找哪个程序运行另一个程序

    我有一个 NAS 运行在 Redhat Linux 的有限版本上 我按照指示破解了它 这样我就可以访问 shell 这很有帮助 我还做了一些修改 其他人也做过修改 除了一个问题之外 它们似乎都工作得很好 不知何故 每隔 22 天 系统就会关
  • 删除 Git 存储库,但保留所有文件

    在我使用 Linux 的过程中的某个时刻 我决定将我的主目录中的所有内容都放入源代码管理中是个好主意 我不是在问这是否是一个好主意 我是在问如何撤销它 删除存储库的原因是我最近安装了 Oh My Zsh 而且我非常喜欢它 问题是我的主目录有
  • 我不明白 execlp() 在 Linux 中如何工作

    过去两天我一直在试图理解execlp 系统调用 但我还在这里 让我直奔主题 The man pageexeclp 将系统调用声明为int execlp const char file const char arg 与描述 execl exe
  • 当 grep "\\" XXFile 我得到“尾随反斜杠”

    现在我想查找是否有包含 字符的行 我试过grep XXFile但它暗示 尾随反斜杠 但当我尝试时grep XXFile没关系 谁能解释一下为什么第一个案例无法运行 谢谢 区别在于 shell 处理反斜杠的方式 当你写的时候 在双引号中 sh
  • “make install”将库安装在 /usr/lib 而不是 /usr/lib64

    我正在尝试在 64 位 CentOS 7 2 上构建并安装一个库 为了这个目的我正在跑步 cmake DCMAKE BUILD TYPE Release DCMAKE INSTALL PREFIX usr DCMAKE C COMPILER
  • 在两次之间每分钟执行一次 Cronjob

    我需要在 crontab 中每分钟运行一个 bash 脚本8 45am and 9 50am每天的 Code 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 8 home pull sh gt ho
  • 我如何知道 C 程序的可执行文件是在前台还是后台运行?

    在我的 C 程序中 我想知道我的可执行文件是否像这样在前台运行 a out 或者像这样 a out 如果你是前台工作 getpgrp tcgetpgrp STDOUT FILENO or STDIN FILENO or STDERR FIL
  • 如何在 bash 上运行 MySQL 命令?

    以下代码在命令行上运行 mysql user myusername password mypassword database mydatabase execute DROP DATABASE myusername CREATE DATABA
  • 如何构建任务“gems:install”

    我正在将 Rails 应用程序部署到 Linux 服务器 并且缺少一些 rake 任务 包括 rake gems install 和 rake db 我正在运行来自 GEM 的 Rails 2 3 4 为什么是这样 我该如何解决 我可以以某
  • 无法在 Unix shell 脚本上操作日期(日期:非法选项 -- d)

    我需要将当前日期添加 10 天并将其分配给变量 但我收到错误 date illegal option d 这是我尝试过的 gt NEW expration DATE date d 10 days Result date illegal op
  • 如何查询X11显示分辨率?

    这似乎是一个简单的问题 但我找不到答案 如何查询 通过 X11 存在哪些监视器及其分辨率 查看显示宏 http tronche com gui x xlib display display macros html and 屏幕宏 http
  • 第二次ftruncate失败

    我试图在首次成功执行 shm open 和 ftruncate 后超出共享内存对象 这是代码 char uuid GenerateUUID int fd shm open uuid O RDWR O CREAT O EXCL S IRUSR
  • 无法在 Perl 中找到 DBI.pm 模块

    我使用的是 CentOS 并且已经安装了 Perl 5 20 并且默认情况下存在 Perl 5 10 我正在使用 Perl 5 20 版本来执行 Perl 代码 我尝试使用 DBI 模块并收到此错误 root localhost perl
  • Linux 上的基准测试程序

    对于一项任务 我们需要使用不同的优化和参数来对我们的实现进行基准测试 有没有一种可行的方法可以在Linux命令行 我知道时间 上使用不同的参数对小程序进行基准测试 从而为我提供CSV或类似内容的时间数据 输出可能类似于 Implementa
  • 每个命令都返回“bash:<命令>:找不到命令...”[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我刚刚安装了 Scala 并添加了路径gedit bashrc export SCALA HOME home avijit sca
  • 如何在 GNU/Linux 上设置 Subversion (SVN) 服务器 - Ubuntu [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我有一台运行 Ubuntu 的笔记本电脑 我想将其用作 Subversion 服务器 既让我自己在本地承诺 也让其他人远程承诺 要使其
  • 如何从 PROC 获取有关子进程的信息

    我正在尝试编写一个以几个进程作为参数的程序 然后父进程执行每个子进程并打印出一些相关的统计信息 示例 generate ls l 将生成一个程序 打印出有关 ls l 的一些统计信息 特别是其系统时间 用户时间和上下文切换次数 我不想使用
  • Fedora dnf 更新不起作用?

    当我尝试使用 update 命令更新 Fedora 22 时 sudo dnf update 我收到以下错误 错误 无法同步存储库 更新 的缓存 无法准备内部镜像列表 Curl 错误 6 无法解析主机名 无法解析主机 mirrors fed
  • 嵌入式linux编写AT命令

    我在向 GSM 模块写入 AT 命令时遇到问题 当我使用 minicom b 115200 D dev ttySP0 term vt100 时它工作完美 但我不知道如何在 C 代码中做同样的事情 我没有收到任何错误 但模块对命令没有反应 有

随机推荐

  • vue报错:regeneratorRuntime is not defined

    报错原因是使用了 async await 没有配置 babel 导致语法不支持 所以才会报错 首先安装以下依赖 npm install babel plugin transform runtime save dev 或 npm i save
  • 【AnyQ】如何添加插件

    一 已有插件 字典插件 此类插件继承DictInterface接口 哈希词典 HashAdapter
  • SyntaxWarning: name 'x' is assigned to before global declaration global color Python

    SyntaxWarning name x is assigned to before global declaration global color Python 这种报错很大原因是在同一个函数重复使用了global 声明 举个例子 x 0
  • LiveData详细分析2

    一 LiveData是什么东西 1 基于观察者设计模式 LiveData是一种持有可被观察数据的类 被观察者 LiveData需要一个观察者对象 一般是Observer类的具体实现 当观察者的生命周期处于STARTED或RESUMED状态时
  • linux用dd命令刻录u盘,巧用linux dd命令刻录启动U盘

    dd命令是Linux UNIX 下的一个非常有用的命令 作用是用指定大小的块拷贝一个文件 并在拷贝的同时进行指定的转换 大部分用户只知道dd命令的这个用处 殊不知dd命令做usb启动盘也十分方便 下面就让我们一起来看看dd命令是如何运用到刻
  • 聊聊限流、熔断和降级

    背景 分布式系统中的调用关系错综复杂 如何保障整个系统平稳运行则显得尤为重要 限流 熔断和降级应运而生 限流 为了保障下游服务稳定性 通常会提前预估调用QPS 一旦超过预估QPS则可以进行限流 拒绝超出预估的请求 常见的限流算法有固定窗口
  • python插入单条、多条dict类型数据到clickhouse

    比如一个数据库名字叫test 表名称叫just check 插入单条dict数据 import clickhouse connect client clickhouse connect get client host 127 0 0 1 d
  • 【剑指offer】总集

    目录 前言 题目索引 数据结构 数 数据结构 数组 数据结构 字符串 数据结构 链表 数据结构 树 数据结构 队列 栈 堆 前言 想看Leetcode总集篇的点它点它 Leetcode总集篇 算法和算法题的任务目标 主要可分为 增 删 改
  • 什么是网站主服务器域名,主域名服务器是什么

    主域名服务器是什么 内容精选 换一换 香港节点和大陆节点的区别如下 香港节点购买域名后无需备案 可以直接在后台绑定域名并使用 大陆节点购买域名后需要先完成备案 才可以在后台绑定域名 香港节点支持绑定多个一级或者子域名 大陆节点只能绑定一个一
  • Linux高性能服务器编程|阅读笔记:第6章 - 高级I/O函数

    目录 简介 6 1 pipe函数 6 2 dup函数和dup2函数 6 3 readv函数和writev函数 6 4 sendfile函数 6 5 mmap函数和munmap函数 6 6 splice函数 6 7 tee函数 6 8 fcn
  • [问题解决方案]JSON parse error: Illegal unquoted character ((CTRL-CHAR, code 13)): has to be escaped using

    公司最近跟外部有一个接受图片的接口让我来做 我心想这么简单 又可以偷懒喽 打开文档一看图片是base64格式的 没啥 不就是base64转字节流吗 一同操作后 测试接受参数 崩出来这个东西 然后就解决呗 总不能因为解决不了让人转变发送参数的
  • 【学习笔记】Python进行数据清洗

    写在前面的话 最近看了一个up主讲基本数据清洗操作 觉得非常好 链接如下 Python 数据清洗 用Python给数据洗澡澡 数据分析 数据清洗 数据预处理 哔哩哔哩 bilibili 评论区也有原数据集和相关代码的链接 不是广告 下面就浅
  • 小程序中scroll-view的下拉刷新和小程序页面的下拉刷新开启方法

    scroll view的下拉刷新 video wxml中
  • ES6---promise详解及用法

    一 什么是Promise Promise是ES6异步编程的一种解决方案 目前最先进的解决方案是async和await的搭配 ES8 但是它们是基于promise的 从语法上讲 Promise是一个对象或者说是构造函数 用来封装异步操作并可以
  • 项目总结之angular4.0中的@viewchild,@Input,@Output

    在项目中遇到了这样一个问题 父页面中需要操作子组件里面的方法 这个时候需要怎么做呢 项目是由ionic3 0和angular4 0构成的 代码如下 child的html页面如下 div class child div class child
  • HDU--3783:ZOJ (水题)

    1 题目源地址 http acm hdu edu cn showproblem php pid 3783 2 源代码 include
  • Java HTTPS客户端如何处理证书

    HTTPS HTTP over Secure Socket Layer 简单讲即HTTP下加入SSL层 HTTPS的安全基础是SSL 参考以前的两篇文章 Java JSSE SSL TLS编程代码实例 单向认证 Java JSSE SSL
  • python-数据分析(12-时间序列)

    Pandas 12 Pandas之时间序列 12 1 时间序列 时间序列前言 时间序列数据在很多领域都是重要的结构化数据形式 比如 金融 神经科学 生态学 物理学 在多个时间点观测的数据形成了时间序列 时间序列可以是固定频率的 也可以是不规
  • 计算机专业论文 方向,计算机专业本科生方向论文题目 计算机专业本科生论文题目怎样取...

    100道 计算机专业本科生方向论文题目供您参考 希望能解决毕业生们的计算机专业本科生论文题目怎样取相关问题 选好题目那就开始写计算机专业本科生论文吧 一 比较好写的计算机专业本科生论文题目 1 对本科生计算机课程教学改革的探讨 2 浅谈对本
  • 《UNIX环境高级编程》笔记 第十三章-守护进程

    1 概念 守护进程 daemon 是生存期长的一种进程 它们常常在系统引导装入时启动 仅在系统关闭时才终止 因为它们没有控制终端 所以说它们是在后台运行的 Linux的大多数服务就是用守护进程实现的 这些守护进程名通常以d结尾 如inetd