zoukankan      html  css  js  c++  java
  • Zookeeper客户端cli_st为何在crontab中运行不正常?

    实践中,发现直接在命令行终端运行cli_st时,能够得到预期的结果,但一将它放到crontab中,则只收到:

    bye

    相关的一段clit_st源代码如下:

            if (FD_ISSET(0, &rfds)) {

                int rc;

                int len = sizeof(buffer) - bufoff -1;

                if (len <= 0) {

                    fprintf(stderr, "Can't handle lines that long! ");

                    exit(2);

                }

                rc = read(0, buffer+bufoff, len);

                if (rc <= 0) {

                    fprintf(stderr, "bye ");

                    break;

                }

                bufoff += rc;

                buffer[bufoff] = '';

                while (strchr(buffer, ' ')) {

                    char *ptr = strchr(buffer, ' ');

                    *ptr = '';

                    processline(buffer);

                    ptr++;

                    memmove(buffer, ptr, strlen(ptr)+1);

                    bufoff = 0;

                }

            }

            zookeeper_process(zh, events);

    经推断和测试,以及借助strace工具调查,发现问题出在了“if (FD_ISSET(0, &rfds)) {”一处。正常它应当不成立的。

    这导致cli_st主动断开了与zookeeper服务端的连接,从zookeeper的服务端日志文件可以看到这个动作:

    caught end of stream exception

    Unable to read additional data from client sessionid 0x2513c8566c1000b, likely client has closed socket

    这段日志显示,cli_st关闭了连接。

    问题的原因即是:

    cronfork子进程后,运行命令之前,会关闭stdin,这样导致clit_st中“if (FD_ISSET(0, &rfds)) {”成立,致使连接被关闭。

    可以通过简单程序观察cron会关闭或重定向了stdint

    #include <errno.h>

    #include <unistd.h>

    #include <stdio.h>

    int main()

    {

            char buf[1024] = {0};

            int n = read(0, buf, sizeof(buf)-1);

            printf("n=%d, errno=%d: %m ", n, errno);

            return 0;

    }

    stdin正常,上面代码的进程会挂住,直接读取到stdinstdin被关闭。但实际结果是:

    n=0, errno=0: Success

    read的返回值为0,表示stdin已关闭或重定向了。

    可借助dup2stdin复活:

    #include <errno.h>

    #include <fcntl.h>

    #include <stdio.h>

    #include <sys/stat.h>

    #include <sys/types.h>

    #include <unistd.h>

    int main()

    {

            char buf[1024] = {0};

            int n = read(0, buf, sizeof(buf)-1);

            printf("n=%d, errno=%d: %m ", n, errno);

            int fd = open("/tmp/abcde", O_RDONLY);

            printf("fd=%d ", fd);

            if (-1 == dup2(fd, 0))

                    printf("dup2 error: %m ");

            n = read(0, buf, sizeof(buf)-1);

            printf("n=%d, errno=%d: %m ", n, errno);

            if (n>0)

            {

                    buf[n]=0;

                    printf("%s ", buf);

            }

            return 0;

    }

    上面这段代码运行结果:

    n=0, errno=0: Success

    fd=3

    n=7, errno=0: Success

    dsfsfd

    要解决Zookeeper客户端cli_stcron中运行的问题,最简单的办法是注释掉下段代码,然后重新编译,以跳过读标准输入:

    bufoff=0; // 当注释下段代码时,需要加上它应付编译器

    buffer[0]=0; // 当注释下段代码时,需要加上它应付编译器

    #if 0

            if (FD_ISSET(0, &rfds)) {

                int rc;

                int len = sizeof(buffer) - bufoff -1;

                if (len <= 0) {

                    fprintf(stderr, "Can't handle lines that long! ");

                    exit(2);

                }

                rc = read(0, buffer+bufoff, len);

                if (rc <= 0) {

                    fprintf(stderr, "bye ");

                    break;

                }

                bufoff += rc;

                buffer[bufoff] = '';

                while (strchr(buffer, ' ')) {

                    char *ptr = strchr(buffer, ' ');

                    *ptr = '';

                    processline(buffer);

                    ptr++;

                    memmove(buffer, ptr, strlen(ptr)+1);

                    bufoff = 0;

                }

            }

    #endif

    cron的实现大致如下,它会将标准输入、输出和出错重定向到/dev/null,这导致后面对stdinread返回0。有关cron的实现,可以浏览cron.chttp://blog.chinaunix.net/uid-20682147-id-5521210.html):

    #include <errno.h>

    #include <fcntl.h>

    #include <stdio.h>

    #include <stdlib.h>

    #include <sys/types.h>

    #include <sys/stat.h>

    #include <unistd.h>

    int main()

    {

            int n;

            char buf[1024];

            // 重定向stdin到/dev/null

            int fd = open("/dev/null", O_RDWR, 0);

            dup2(fd, 0); // 重定向0到fd,0即为stdin

            pid_t pid = fork();

            if (0 == pid)

            {

                    n = read(0, buf, sizeof(buf)-1); // 返回0

                    printf("n=%d, errno=%d: %m ", n, errno);

                    exit(0);

            }

            return 0;

    }

    相关文章:

    http://blog.chinaunix.net/uid-20682147-id-4977039.htmlCron运行原理)

    dup&dup2

    fid = dup(fildes);

    等同于

    fid = fcntl(fildes, F_DUPFD, 0);

    fidfildes都指向fildes

    fid = dup2(fildes, fildes2); // 重定向fildes2fildes

    等同于:

    close(fildes2);

    fid = fcntl(fildes, F_DUPFD, fildes2);

    fidfildesfildes2指向fildes


  • 相关阅读:
    利用 StartLoadingStatus 和 FinishLoadingStatus 读取数据特别是大数据时增加渐隐渐显等待特效
    在Indicator中添加动态Checkbox,无需绑定数据源,支持全选
    修复DBGrideh使用TMemTableEh在Footers求平均值为0的Bug
    字符串操作之格式化
    关于C#里面SQLite读取数据的操作
    多线程“尚未调用coinitialize” 报错
    自动化脚本运行稳定性(一)——脚本健壮性
    接口测试用例编写规范
    测试计划对应用质量的影响
    MySQL数据操作语句精解
  • 原文地址:https://www.cnblogs.com/aquester/p/9891556.html
Copyright © 2011-2022 走看看