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

bye

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

if (FD_ISSET(, &rfds)) {

int rc;

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

if (len <= 0) {

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

exit(2);

}

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

if (rc <= 0) {

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(, &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关闭了连接。

问题的原因即是:

cron在fork子进程后,运行命令之前,会关闭stdin,这样导致clit_st中“if (FD_ISSET(, &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", n, errno);

return 0;

}

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

n=0, errno=0: Success

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

可借助dup2让stdin复活:

#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", 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_st在cron中运行的问题,最简单的办法是注释掉下段代码,然后重新编译,以跳过读标准输入:

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!\n");

exit(2);

}

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

if (rc <= 0) {

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,这导致后面对stdin的read返回0。有关cron的实现,可以浏览cron.c(http://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", n, errno);

exit(0);

}

return 0;

}

相关文章:

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

dup&dup2:

fid = dup(fildes);

等同于

fid = fcntl(fildes, F_DUPFD, 0);

fid和fildes都指向fildes。

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

等同于:

close(fildes2);

fid = fcntl(fildes, F_DUPFD, fildes2);

fid、fildes和fildes2指向fildes。

Zookeeper客户端cli_st为何在crontab中运行不正常?的更多相关文章

  1. Nodejs的安装配置及如何在sublimetext2中运行js

    Nodejs的安装配置及如何在sublimetext2中运行js听语音 | 浏览:4554 | 更新:2015-06-16 11:29 Nodejs的安装配置及如何在sublimetext2中运行js ...

  2. 如何在xampp中运行php文件 (WINDOWS)

    from:http://blog.sina.com.cn/s/blog_5e87822501011os2.html 入门: 如何在xampp中运行php文件 (WINDOWS) 安装XAMPP启动ap ...

  3. [转帖]如何在VirtualBox中运行macOS Catalina Beta版本

    如何在VirtualBox中运行macOS Catalina Beta版本 secist2019-08-03共2179人围观系统安全 https://www.freebuf.com/articles/ ...

  4. 如何在 crontab 中让 source ~/.bashrc 生效

    cron 是许多类 Unix 操作系统中都自带的用来调度定时任务的工具,定时任务的配置是写在 crontab 文件中的,但是 crontab 文件不允许直接编辑,一般都是通过命令 crontab -e ...

  5. crontab中运行python程序出错,提示ImportError: No module named解决全过程

    将一个python脚本放入crontab执行时,提示如下错:ImportError: No module named hashlib但是在shell中直接执行时没有任何问题,google之后,得到线索 ...

  6. 如何在linux中运行sql文件

    1.在linux中进入sql命令行 mysql -u root -p   输入密码 2.假设home下面有a.sql文件 先得use databasename,要不会报错 “No Database S ...

  7. 如何在cygwin中运行crontab定时脚本[利刃篇]

    用到cygwin,自然是希望能多处理一些类似linux的任务了,那就自然少不了定时任务crontab,看到网上教程不少,自己运行一个测试却也不那么容易,下面就记录我的安装过程,以供参考吧! 1.首先, ...

  8. 如何在Apache中运行Python脚本

    第一步:进入C:\Apache24\cgi-bin: 第二步:在cgi-bin目录下新建一个hello.py文件: 第三步: #!python #coding:utf-8 print("co ...

  9. 如何在cmd中运行数据库

    在开始菜单中输入cmd 在控制板输入:net  start  MSSQLserver 启动数据库 在控制板输入:net  stop  MSSQLserver 关闭数据库 在控制板输入:net  pur ...

随机推荐

  1. IntelliJ IDEA 基础设置

    原文地址:IntelliJ IDEA 基础设置 博客地址:http://www.extlight.com 一.前言 IDEA 全称 IntelliJ IDEA,是java语言开发的集成环境,Intel ...

  2. mark TODO:完善拦截规则;日志分析;web仪表盘展示;终极目标动态配置规则

  3. php常量的实现

    1.php的常量 就是一个简单的标识符,脚本执行期间不会改变,大小写敏感,默认大写. 常量的存储结构 typedef struct _zend_constant { zval value; //常量值 ...

  4. [转][C#]常用开源项目

    本文来自:http://www.cnblogs.com/sunxuchu/p/6047589.html 新增两个: 纸壳CMS http://www.zkea.net/zkeacms https:// ...

  5. 使用libssh2连接到远程服务器

    libssh2-1.7.0.tar.gz  示例代码:libssh2-1.7.0.tar.gz\libssh2-1.7.0\example 官网示例 https://www.libssh2.org/e ...

  6. tomcat启动时SessionIdGeneratorBase.createSecureRandom耗时5分钟的问题

    通常情况下,tomcat启动只要2~3秒钟,突然有一天,tomcat启动非常慢,要花5~6分钟,查了很久,终于在这篇文章找到了解决方案,博主牛人啊. 原文参见:http://blog.csdn.net ...

  7. springboot中对yaml文件的解析

    一.YAML是“YAML不是一种标记语言”的外语缩写 (见前方参考资料原文内容):但为了强调这种语言以数据做为中心,而不是以置标语言为重点,而用返璞词重新命名.它是一种直观的能够被电脑识别的数据序列化 ...

  8. 关于Ceph现状与未来的一些思考

    http://blog.csdn.net/mightysheldor/article/details/51093476 Ceph从2004年提交了第一行代码,至今为止已经10年了.这个起源于Sage博 ...

  9. ES6系列_4之扩展运算符和rest运算符

    运算符可以很好的为我们解决参数和对象数组未知情况下的编程,让我们的代码更健壮和简洁. 运算符有两种:对象扩展运算符与rest运算符. 1.对象扩展( spread)运算符(...) (1)解决参数个数 ...

  10. 「小程序JAVA实战」小程序的视频点赞功能开发(62)

    转自:https://idig8.com/2018/09/24/xiaochengxujavashizhanxiaochengxudeshipindianzangongnengkaifa61/ 视频点 ...