Zookeeper客户端cli_st为何在crontab中运行不正常?

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: Zookeeper客户端cli_st为何在crontab中运行不正常?.pdf 实践中,发现直接在命令行终端运行cli_st时,能够得到预期的结果,但一将它放到crontab中,则只收到: bye   相关的一段clit_st源代码如下: ...
img_e25d4fb2f8de1caf41a735ec53088516.pngZookeeper客户端cli_st为何在crontab中运行不正常?.pdf

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

bye

 

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

        if (FD_ISSET(0, &rfds)) {

            int rc;

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

            if (len 

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

                exit(2);

            }

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

            if (rc 

                fprintf(stderr, "bye\n");

                break;

            }

            bufoff += rc;

            buffer[bufoff] = '\0';

            while (strchr(buffer, '\n')) {

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

                *ptr = '\0';

                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 

#include 

#include 

int main()

{

        char buf[1024] = {0};

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

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

        return 0;

}

 

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

n=0, errno=0: Success

 

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

 

可借助dup2stdin复活:

#include 

#include 

#include 

#include 

#include 

#include 

 

int main()

{

        char buf[1024] = {0};

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

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

 

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

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

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

                printf("dup2 error: %m\n");

 

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

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

        if (n>0)

        {

                buf[n]=0;

                printf("%s\n", 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 

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

                exit(2);

            }

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

            if (rc 

                fprintf(stderr, "bye\n");

                break;

            }

            bufoff += rc;

            buffer[bufoff] = '\0';

            while (strchr(buffer, '\n')) {

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

                *ptr = '\0';

                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 

#include 

#include 

#include 

#include 

#include 

#include 

 

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", 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


相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
4天前
|
Java API Apache
ZooKeeper【基础 03】Java 客户端 Apache Curator 基础 API 使用举例(含源代码)
【4月更文挑战第11天】ZooKeeper【基础 03】Java 客户端 Apache Curator 基础 API 使用举例(含源代码)
23 11
|
12天前
|
存储
ZooKeeper客户端常用命令
ZooKeeper客户端常用命令
24 1
|
3月前
|
安全 Java API
Zookeeper(持续更新) VIP-02 Zookeeper客户端使用与集群特性
2,/usr/local/data/zookeeper-3,/usr/local/data/zookeeper-4,在每个目录中创建文件。创建四个文件夹/usr/local/data/zookeeper-1,/usr/local/data/zookeeper-Follower:只能处理读请求,同时作为 Leader的候选节点,即如果Leader宕机,Follower节点。己对外提供服务的起始状态。E: 角色, 默认是 participant,即参与过半机制的角色,选举,事务请求过半提交,还有一个是。
|
3月前
Zookeeper的客户端的命令
Zookeeper的客户端的命令
18 0
|
3月前
|
缓存 Java API
Zookeeper(持续更新) VIP-02 Zookeeper客户端使用与集群特性
Curator 是一套由netflix 公司开源的,Java 语言编程的 ZooKeeper 客户端框架,Curator项目是现在ZooKeeper 客户端中使用最多,对ZooKeeper 版本支持最好的第三方客户端,并推荐使用,Curator 把我们平时常用的很多 ZooKeeper 服务开发功能做了封装,例如 Leader 选举、分布式计数器、分布式锁。这就减少了技术人员在使用 ZooKeeper 时的大部分底层细节开发工作。
|
3月前
|
Apache
Apache ZooKeeper - 构建ZooKeeper源码环境及StandAlone模式下的服务端和客户端启动
Apache ZooKeeper - 构建ZooKeeper源码环境及StandAlone模式下的服务端和客户端启动
46 2
|
8月前
|
API
Zookeeper学习---2、客户端API操作、客户端向服务端写数据流程
Zookeeper学习---2、客户端API操作、客户端向服务端写数据流程
Zookeeper学习---2、客户端API操作、客户端向服务端写数据流程
|
4月前
|
存储 设计模式 算法
深入浅出Zookeeper源码(六):客户端的请求在服务器中经历了什么
当我们向zk发出一个数据更新请求时,这个请求的处理流程是什么样的?zk又是使用了什么共识算法来保证一致性呢?带着这些问题,我们进入今天的正文。
136 1
深入浅出Zookeeper源码(六):客户端的请求在服务器中经历了什么
|
4月前
|
存储 设计模式 算法
深入浅出Zookeeper源码(六):客户端的请求在服务器中经历了什么
当我们向zk发出一个数据更新请求时,这个请求的处理流程是什么样的?zk又是使用了什么共识算法来保证一致性呢?带着这些问题,我们进入今天的正文。
117 0
|
4月前
|
Java API Apache
ZooKeeper【基础 03】Java 客户端 Apache Curator 基础 API 使用举例(含源代码)
ZooKeeper【基础 03】Java 客户端 Apache Curator 基础 API 使用举例(含源代码)
24 0