一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
Linux 默认打开的三个文件
前面有一篇文章:
juejin.cn/post/708151…
讲解了管道操作符的一些概念。
里面提及了Linux文件的一些东西,这里要说的是,任何Linux进程都会默认打开的三个文件:
- 标准输入,描述符为
0
,默认就是键盘输入。 - 标准输出,描述符为
1
,默认就是输出到屏幕。 - 标准输出,描述符为
2
,默认还是输出到屏幕, 所以一般情况下,正常日志和错误日志我们都会看见打印在屏幕上,但是他们在这种描述符的概念下,确实是两个文件,只不过最终的硬件是同一个而已。
Linux进程通信
关于进程间通信,方式太多了。
比如说,我本地的一台机器的浏览器程序能够和远程服务器的一个http服务器程序,就能很好的通信,所以我才能用浏览器上网。
这就是一种进程间通信,不过这太宽泛了。
现在要说的就是同一台机器上,两个进程之间通信方式。
有很多种,这里要说的一种是非常方便的,比较好用的,编码容易的:
- 利用文件,准确来说,利用
标准输入
和标准输出
一个任务分发系统
假设你有一个任务分发程序
和一堆任务处理程序
,任务分发程序
会收到很多任务,然后把他们分发到各个任务处理程序
中。
比如说,按照任务的某个字段,分发给不同的程序。比如说按照任务的来源IP,进行哈希,然后分发到后面的任务处理程序中。
这种系统很常见,比如说,nginx的反向代理就是这样的,反向代理的upstream可以设置多个,进行负载均衡。
这里我们只处理一个问题:任务收集进程
如何发送消息到任务处理进程
?
你会想到,利用http
,这当然行。
http
协议简单好用,且在大部分场景下,基本上算是一个没法缺少的组件,用http协议当然很好。
不过利用标准输入标准输出可能更好,如果你的业务逻辑不是很复杂的话。
因为标准输入标准输出,不用占用端口,这样一来任务处理程序
随便启动即可。
在程序里利用标准输入来驱动逻辑
大部分情况下,一个服务型的程序不会用到标准输入,因为标准输入默认情况下都是键盘。一个服务型的程序基本上都是以后台进程的形式存在,根本不会有人用键盘往里面输入数据。
但是就算你用后台进程的形式启动一个程序,这个程序也还是打开了标准输入这个文件,不管你读取或者没有读取,这个文件本身是打开的。
我们可以在程序里一直读取这个标准输入,按照自己定义的通信协议来分割内容,解码成任务具体的字段。
比如说,一行就是一个任务输入,而且每一行都是一个json
。
这样一来,我们只需要搞一个死循环来读取标准输入就行了。
程序的写法很简单,就类似于处理文件一样,这个文件的格式就是一行一个json。我们假设我们的程序是读取标准输入,然后打印出来。
我们将这个程序放到Linux下,直接在命令行跑起来,这个时候程序会卡住,因为他在读取标准输入,也就是你键盘输入,此时你随便输入点什么,都可以被程序读到。
我们这个时候需要把键盘输入
换成另一个程序往里面输入
,这才成功。
简单,我们打开另一个terminal
,找到这个卡住的程序的pid
。
ps aux|grep xxx
找到pid
之后,我们进去这个目录:
cd /proc/xxx/fd
然后:
echo "hello world" > 0
你会发现,那个被卡住的程序,此时输出了一个:
hello world
这就是最重要的一步,我们通过进程pid,找到了这个进程打开的标准输入文件:/proc/xxx/fd/0
,然后用echo
命令,往/proc/xxx/fd/0
里输出了一行hello world
。
这个时候,我们完全没用到键盘输入,也成功的向刚刚卡住的进程里输入了一段hello world
!
任务分发程序
任务分发程序
,需要不断的往任务处理程序
发送信息。
为了将这两个进程逻辑解耦,我们规定:任务分发程序
将任务信息发送到自身的标准输出中。
发送的格式就是,一行一个json。
好,此时我们启动两个程序,如果没问题的话,任务分发程序
会一直往屏幕上打印信息,一行一个json。
我们将这个任务分发程序
利用nohup
的方式启动,此时默认会创建一个nohup.out
的文件,里面就是标准输出。
我们找到这个任务分发程序
的pid。
然后 :
tail -f /proc/任务收集程序pid/1
会发现,能够获取到打印的信息。
此时最关键的一步来了:
tail -f /proc/任务分发程序pid/1 > /proc/任务处理程序pid/0
你会发现,任务分发程序
的输出,成功发送到了任务处理程序
。
这样做的好处
-
简单,不用多余的网络协议,比如说http或者tcp。
-
文件读写,在任何语言里都是基础的,不用安装多余库
-
利用中间程序,可以随时挂接信息源和信息消费者,比较弹性