Linux 下进程通信之标准输入输出

1,391 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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。

  • 文件读写,在任何语言里都是基础的,不用安装多余库

  • 利用中间程序,可以随时挂接信息源和信息消费者,比较弹性