一个echo引起的进程崩溃

简介:
最近在编写后台程序时遇到一个问题。发现后台程序总是莫名其妙的die掉。经排查,发现罪魁祸首是一个echo。
案情重现:
1.ssh登陆服务器

2.新建一个php文件test.php,代码如下:


<?php
sleep(50);
echo "aaa\n";
file_put_contents("/tmp/test.txt",time());
?>

3.用以下命令执行test.php程序
$ php test.php &
查看 /tmp/test.txt 文件的内容为 1381325659
4.然后再次执行如下命令。命令执行后,马上使用exit命令退出登陆
$ php test.php &
5.然后ssh登陆服务器,发现/tmp/test.txt 文件的内容依然是 1381325659。说明第二次执行test.php时,file_put_contents函数没有执行,或者没有执行成功。

追查真凶
为什么第二次执行的时候file_put_contents函数没有执行,或者没有执行成功?
让我们使用万能的strace命令查看下程序执行过程中,系统调用情况。
正常情况下,strace结果中会有如下显示:
nanosleep({50, 0}, {50, 0}) = 0
write(1, "aaa\n", 4aaa
) = 4
lstat("/tmp/test.txt", {st_mode=S_IFREG|0644, st_size=10, ...}) = 0
lstat("/tmp", {st_mode=S_IFDIR|S_ISVTX|0777, st_size=1576960, ...}) = 0
open("/tmp/test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lseek(3, 0, SEEK_CUR) = 0
write(3, "1381326235", 10) = 10
close(3) = 0
close(2) = 0
close(1) = 0
munmap(0x2b4dd1414000, 4096) = 0
close(0) = 0

如果退出ssh后,再登陆,strace结果中会有如下显示:
write(1, "aaa\n", 4) = -1 EIO (Input/output error)
close(2) = 0
close(1)
munmap(0x2b4412622000, 4096) = 0
close(0) = 0

注意两次strace的结果蓝色部分。根据strace结果,可以肯定是因为echo时产生了EIO错误导致进程终止,最终没有执行file_put_contents函数。

一追到底
为什么退出登陆后,再登陆,就会发生EIO错误呢?这个和linux的会话处理有关。
当用户ssh登陆一个服务器时,也就开始了一个会话。会话开始后,标准输入(stdin)、标准输出(stdout)、标准错误(stderr)会连接到一个对应的终端(pty)。

用户登陆后,任何标准输出都会在终端中有反应。标准输出的文件句柄是1。因此,php中的echo("aaa\n") 会导致执行系统调用write(1, "aaa\n", 4). 会在终端中写aaa\n。

​当用户退出登陆时,一个会话就结束了。会话结束时,修改所有打开该终端的文件句柄,改成不可读也不可写;

​用户退出登陆后再执行write(1, "aaa\n", 4),会报EIO错误。因为终端句柄已经不可写。EIO错误发生后,导致进程结束。

解决办法
方法一:
​使用重定向符号&把标准输出重定向到空洞。
$ php test.php > /dev/null 2 >&1 &
方法二:
使用nohup。[推荐使用此方法]
$ nohup php test.php &


目录
相关文章
|
6月前
|
安全 Linux 开发者
⭐⭐⭐⭐⭐Linux C/C++ 进程崩溃诊断以及有效数据收集:解锁代码问题快速定位与修复的方法
⭐⭐⭐⭐⭐Linux C/C++ 进程崩溃诊断以及有效数据收集:解锁代码问题快速定位与修复的方法
393 1
|
存储 缓存 监控
腾讯三面:进程写文件过程中,进程崩溃了,文件数据会丢吗?
腾讯三面:进程写文件过程中,进程崩溃了,文件数据会丢吗?
191 0
腾讯三面:进程写文件过程中,进程崩溃了,文件数据会丢吗?
|
Python
解决办法:C向Python传递字串数组导致进程崩溃
解决办法:C向Python传递字串数组导致进程崩溃
137 0
|
Shell Linux
linux下监视进程 崩溃挂掉后自动重启的shell脚本
如何保证服务一直运行?如何保证即使服务挂掉了也能自动重启?在写服务程序时经常会碰到这样的问题。在Linux系统中,强大的shell就可以很灵活的处理这样的事务。     下面的shell通过一个while-do循环,用ps -ef|grep 检查loader进程是否正在运行,如果没有运行,则启动,这样就保证了崩溃挂掉的进程重新被及时启动。
3205 0
|
5月前
|
监控 Linux 应用服务中间件
探索Linux中的`ps`命令:进程监控与分析的利器
探索Linux中的`ps`命令:进程监控与分析的利器
119 13
|
4月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
4月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
147 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
3月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。