解决僵死进程defunct方式

Publish: September 14, 2017 Category: C/C++ No Comments

这里有以下几种方式解决僵死进程:

忽略子进程退出信号

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <strings.h>

void sig_catch( int sig, void (*f) () )
{
    struct sigaction sa;
    sa.sa_handler = f;
    sa.sa_flags   = 0;
    sigemptyset(&sa.sa_mask);
    sigaction(sig, &sa, (struct sigaction *) 0);
}

sig_catch(SIGCHLD, SIG_IGN);


2. 父进程wait子进程退出信号

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <strings.h>

#define wait_crashed(w) ((w) & 127)
#define wait_exitcode(w) ((w) >> 8)

int wait_pid(int *wstat, int pid)
{
    int r;
    do
        r = waitpid(pid, wstat, 0);
    while ((r == -1) && (errno == EINTR));
    return r;
}


int main(int argc, char **argv) 
{
    pid_t   pid;

    switch (pid = fork()) {
        case -1:
            printf("fork error\n");
            return 1;
        case 0:
            printf("child[%d]: exit\n");
            _exit(31);
    }

    int wstat;
    int exitcode;

    int pid_w = wait_pid(&wstat, pid);
    if (pid_w != pid) {
        printf("waitpid fail. pid_w[%lld] pid[%lld]\n", pid_w, pid);
        return 1;
    }
    
    if (wait_crashed(wstat)) {
        printf("waitpid crashed \n");
        return 1;
    }
    
    exitcode = wait_exitcode(wstat);
    printf("child[%lld] exit code[%d]\n", pid, exitcode);

    return 0;
}


3. Catch子进程信号,并在处理函数内wait (注意这个函数里不可以做syslog调用,在大量并发时会程序异常)

// 此函数内不可调用syslog
void sigchld_exit()
{
    int exitcode;
    int wstat, pid;
    while ((pid = waitpid(-1, &wstat, WNOHANG)) > 0) {
        //log_info("child[%ld] exit[%d]", pid, wstat);
        if (wait_crashed(wstat)) {
            //log_error("child[%ld] crashed[%d]", pid, wstat);
            return;
        }   
        exitcode = wait_exitcode(wstat);
        //log_info("child[%ld] exitcode[%d]", pid, exitcode);
    }   
}

{
    sig_catch(SIGCHLD, sigchld_exit);
}

inetd,xinetd守护进程

Publish: August 31, 2017 Category: Shell,C/C++ No Comments

    inetd, xinetd 为每一个服务都建立侦听socket,当inetd,xinetd收到连接时,它首先确定该socket协议和端口所对应的服务程序,然后fork子进程来启动exec该服务程序,并把连接的通信socket描述符作为标准输入、标准输出和标准错误输出描述符传递给子进程。

    这种方式,不但不需要为每个服务启动独立的服务程序,而且在设计这些服务程序时,还可以避免考虑复杂的socket编程,所需的仅仅是简单的字符串分析。比如telnet、ftp等,都是通过 inetd, xinetd 守护进程来实现的。


xinetd:

  1. 设置文件: /etc/services

# 在文件尾添加一行:
sj    20227/tcp

此文件记录了 xinetd 守护的每个服务的基本信息,包括名称、端口号和协议类型。此例添加了服务 sj 占用TCP协议的20227端口。


  2. 设置文件: /etc/xinetd.d/sj

service sj
{
    socket_type = stream
    protocol    = tcp 
    wait        = no
    user        = root
    only_from   = 198.72.5.0 localhost  
    banner      = /usr/home/grayson/deny_banner
    server      = /usr/home/grayson/sj_server
}

这是一个常见的服务配置文件。我们逐行看一下:

  • 第一行指定这是一个服务并给服务取一个名称。

  • socket_type 描述连接如何工作,常常是 stream(用于 TCP 连接)或 dgram(用于 UDP 服务)。

  • wait 控制 xinetd 是每次处理一个连接 (wait=yes),还是每次处理多个连接 (wait=no)。

  • user 指定守护进程应该作为哪个用户运行。这个用户常常是根用户(超级用户),但是某些服务最好或必须作为服务的创建者运行。

  • only_from 指定哪些系统可以对这个服务发出请求。在这里,只允许 198.72.5 子网上的系统和本地主机使用 sj 服务。最右边的 0 作为通配符;允许 IP 地址前缀为 198.72.5 的任何系统请求服务。可以使用多种表示法指定系统;详情参见 xinetd.conf 手册页。(输入 man 5 xinetd.conf。)如果允许所有就去掉这行!

  • 如果禁止访问,就把 /usr/local/etc/deny_banner 文件的内容发送给客户机。

  • 最后,server 指定允许访问时运行的可执行程序。


  3. 重启服务:

service xinetd restart

    

  4. 服务: sj_server

#include <stdio.h>
int main()
{
    char buf[1024] = {0};
    printf("Welcome!\n");
    fflush(stdout);
    while (1) {
        fgets(buf, sizeof(buf), stdin);     // 读取请求
        printf("Input: %s", buf);           // 返回应答
        fflush(stdout);
        if (strncmp(buf, "exit", 4) == 0)
            break;
    }
    return 0;
}

  5. 编译

# gcc -g -o sj_server sj_server.c


Smail删除队列中的文件

Publish: August 9, 2017 Category: 个人 No Comments

1. 获取队列MID号:

# /var/qmail/bin/smailctl qinfo
Aug 09 06:01:13 +0800 CST mid:63399927918638  size:777  <> 
        remote  123@aabbcc.com
Aug 08 14:30:10 +0800 CST mid:2482662363340  size:2332  <> 
        remote  456@cdef.com

2. 获取该队列的hash位置:

# tree /var/qmail/queue/info/ |grep -B1 63399927918638
├── 4
│   └── 63399927918638

3. 删除信封和信体文件:

# rm -f /var/qmail/queue/info/4/63399927918638
# rm -f /var/qmail/queue/mess/4/63399927918638


一行命令查询出所在hash:

#/var/qmail/bin/smailctl qinfo |grep ' mid:' |awk -F' mid:' '{print $2}' |awk '{print "tree /var/qmail/queue/info |grep -B1 "$1}' |sh
└── 9
    └── 6439711977012
├── 13
│   └── 119909357986622524
├── 15
│   └── 7884062363327
├── 16
│   └── 119909521195720018
├── 19
│   └── 9592328016178
├── 20
│   └── 4882731976441
├── 21
│   ├── 5631502363341
│   ├── 5631502363341
│   └── 64876127918686
│   ├── 74365027918567
│   └── 90805427918544
├── 22
│   ├── 3397551976426
│   ├── 3397551976426
│   ├── 74365027918567

然后再去处理

CentOS一键升级内核并开启Google BBR

Publish: April 21, 2017 Category: Shell No Comments

Google BBR是一款TCP加速工具,类似与锐速,Google开源了BBR 拥塞控制算法,并提交到了 Linux 内核,最新的 4.9 版内核已经用上了该算法。因此要想使用BBR,必须升级到最新内核。


查看架构

OpenVZ虚拟化不支持单独升级内核,因此可以直接放弃。KVM、XEN等虚拟化一般是支持的。CentOS执行下面的命令可以查看当前使用的虚拟化技术,详细说明请参考:

#安装virt-whatyum 
install virt-what

#查看架构
virt-what

升级内核并开启BBR

依次执行下面的命令升级内核并开启BBR,执行完毕后需重启服务器,若内核升级失败导致系统无法启动,可以参考《CentOS 6修改启动内核》处理,升级前重要数据请做好备份,勿在生产环境测试。

#分别执行下面的命令升级内核
wget --no-check-certificate https://github.com/teddysun/across/raw/master/bbr.sh
chmod +x bbr.sh
./bbr.sh

查看

#查看内核版本,一般返回4.9
uname -r

#执行下面命令,一般返回net.ipv4.tcp_available_congestion_control
sysctl net.ipv4.tcp_available_congestion_control

#下面命令一般返回net.ipv4.tcp_congestion_control = bbr
sysctl net.ipv4.tcp_congestion_control

#下面命令一般返回net.core.default_qdisc = fq
sysctl net.core.default_qdisc

#返回值有 tcp_bbr 模块,说明BBR已启动

其它说明

一键脚本在Vultr测试通过,该脚本还适用于Debian 7+,Ubuntu 12+,具体请自行尝试。配合秋水逸冰的另一脚本CentOS一键安装shadowsocks脚本效果更佳。


本文引用: CentOS一键升级内核并开启Google BBR

联通在线打印发票流程

Publish: November 22, 2016 Category: 默认分类 No Comments

http://www.10010.com/bj/


充值交费:

    首页 --- 点击‘交费充值’ --- 输入手机号,交费金额选其它(自己填写100) --- 下一步 走充值流程


打印发票:

    首页 --- 话费查询 --- 电子发票查询及开具 --- 实缴发票 --- 点选要开的发票 --- 右侧点“立即开电子发票” --- 输入手机号和邮箱 --- 下一步 确认办理

    收到短信后,刷新本页,该电子发票状态从‘开票中’变为‘可下载’, 点选后,右侧点击下载电子发票(PDF)