Zookeeper客户端cli_st为何在crontab中运行不正常?
实践中,发现直接在命令行终端运行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中运行不正常?的更多相关文章
- Nodejs的安装配置及如何在sublimetext2中运行js
Nodejs的安装配置及如何在sublimetext2中运行js听语音 | 浏览:4554 | 更新:2015-06-16 11:29 Nodejs的安装配置及如何在sublimetext2中运行js ...
- 如何在xampp中运行php文件 (WINDOWS)
from:http://blog.sina.com.cn/s/blog_5e87822501011os2.html 入门: 如何在xampp中运行php文件 (WINDOWS) 安装XAMPP启动ap ...
- [转帖]如何在VirtualBox中运行macOS Catalina Beta版本
如何在VirtualBox中运行macOS Catalina Beta版本 secist2019-08-03共2179人围观系统安全 https://www.freebuf.com/articles/ ...
- 如何在 crontab 中让 source ~/.bashrc 生效
cron 是许多类 Unix 操作系统中都自带的用来调度定时任务的工具,定时任务的配置是写在 crontab 文件中的,但是 crontab 文件不允许直接编辑,一般都是通过命令 crontab -e ...
- crontab中运行python程序出错,提示ImportError: No module named解决全过程
将一个python脚本放入crontab执行时,提示如下错:ImportError: No module named hashlib但是在shell中直接执行时没有任何问题,google之后,得到线索 ...
- 如何在linux中运行sql文件
1.在linux中进入sql命令行 mysql -u root -p 输入密码 2.假设home下面有a.sql文件 先得use databasename,要不会报错 “No Database S ...
- 如何在cygwin中运行crontab定时脚本[利刃篇]
用到cygwin,自然是希望能多处理一些类似linux的任务了,那就自然少不了定时任务crontab,看到网上教程不少,自己运行一个测试却也不那么容易,下面就记录我的安装过程,以供参考吧! 1.首先, ...
- 如何在Apache中运行Python脚本
第一步:进入C:\Apache24\cgi-bin: 第二步:在cgi-bin目录下新建一个hello.py文件: 第三步: #!python #coding:utf-8 print("co ...
- 如何在cmd中运行数据库
在开始菜单中输入cmd 在控制板输入:net start MSSQLserver 启动数据库 在控制板输入:net stop MSSQLserver 关闭数据库 在控制板输入:net pur ...
随机推荐
- (转)为C# Windows服务添加安装程序
本文转载自:http://kamiff.iteye.com/blog/507129 最近一直在搞Windows服务,也有了不少经验,感觉权限方面确定比一般程序要受限很多,但方便性也很多.像后台运行不阻 ...
- 简化Redis数据访问代码RedisTemplate
---恢复内容开始--- Redis数据结构简介: Redis可以存储键与5中数据结构类型之间的映射,这5中数据结构类型分别是;String(字符串),List(列表),Set(集合),Hash(散列 ...
- Bootstrap-Other:UI 编辑器
ylbtech-Bootstrap-Other:UI 编辑器 1.返回顶部 1. Bootstrap UI 编辑器 以下是 15 款最好的 Bootstrap 编辑器或者是在线编辑工具. 1. Boo ...
- [win10]遇坑指南
好多不好用的地方,现在解决的差不多了,把经验分享一下,也方便自己下一次重装 win10 时不再进坑. 1. 输入法:https://zhidao.baidu.com/question/45942172 ...
- JavaScript(一) - 精简
javascript一 javascript 是什么? 1. 运行在浏览器端 ,定义网页的行为, 2.所有的html页面都有js. 二 javascript 定义方式? 1 在html文件里 js 可 ...
- [maven] 实战笔记 - maven 安装配置
1.下载地址http://maven.apache.org/download.html 2.windows下安装maven(1)下载 apache-maven-3.0-bin.zip 解压到任意目录下 ...
- django-聚合操作
聚合操作就是对数据库的数值类型操作的方法 avg,sum,max,min,count select avg(age) from students # 求年龄平均值 django中的聚合操作 1.a ...
- django-DIL模板自定义过滤器,自定义标签,自定义包含标签
自定义过滤器 DTL模板语言生来只是为了方便的展示信息,所以与编程语言相比显得有点薄弱,有时候不能满足我们的需求.因此django提供了一个接口,让开发者能自定义标签和过滤器. 首先,你需要添加一个t ...
- PHP报错open_basedir restriction in effect
问题是出现在了PHP.INI上面了 原因是php.ini里设置了 open_basedir=/var/web/w0895/:/tmp:/usr/lib/php 这里加上相关的目录就可以了 解答:其实o ...
- Django的学习之路
Django基础 Django框架基础 http协议及web框架 Django-2的路由层(URLconf) Django的视图层 Django框架之第三篇模板语法(重要!!!) Django框架之模 ...