强制CLI使用现有流程?

时间:2014-10-29 17:12:04

标签: linux command-line-interface

将消息发送到我的linux守护程序应用程序的最简单方法是什么? myapp foo bar是否可以调用回调而不是启动新进程?什么是与守护进程通信的标准方法?我最合理的选择是将PID粘贴在/var/run中并创建命名管道或套接字?

什么是在命令行上运行的应用程序与其守护程序进程通信的标准方式?当我输入myapp foo bar时,我假设无法让linux调用回调?

2 个答案:

答案 0 :(得分:11)

  

什么是在命令行上运行的应用程序与其守护程序进程通信的标准方式?

有很多方法可以做到这一点:

Dropbox和信号

正在使用各种位置存储&#34; pid文件&#34;包含守护程序的进程ID号:/var/run/<app>/<app>.pid/var/run/<app>.pid(感谢@Adam Katz进行编辑),/run/<app>/<app>.pid/run/<app>.pid,(请参阅Askubuntu: Why has /var/run been migrated to /run? )。

当守护进程的pid已知时,命令行程序(作为单独进程运行)可以通过以下方式与守护进程通信:

  1. 在预先安排好的地方写点东西。这可以是普通文件,数据库表或服务器可读的任何方便点。
  2. 向守护程序发送信号。在本地执行此操作的常用方法是使用kill系统调用int kill(pid_t pid, int sig);
  3. Old School示例:服务器多路复用守护程序xinetd将在收到SIGHUP后重新读取其配置文件。

    发送信号方法已被inotify API冗余,因此进程可以订阅文件系统事件。当您不希望守护程序对每个文件更改进行操作时,使用信号非常有用,因为并非每次更改都可能使文件处于有效状态,如修改系统配置文件时。

    FIFO或管道

    fifo或pipe只是一个特殊文件,它阻止进程读取它,直到其他进程写入它为止。您可以使用mkfifo在文件系统中创建命名管道/ fifo。关于这一点唯一棘手的问题是管道通常应该是无缓冲的,例如,使用open()而不是fopen()。脚本语言有时会为管道友好的读/写提供便利:Perl设置了line-buffered模式,其中$|=1对管道非常有用。

    更常见的是,您会在命令行上看到匿名管道,并使用|符号分隔命令,这些命令作为单独的进程执行。

    套接字

    像mySQL这样的新东西怎么样? mysql数据库系统由命令行客户端mysql和服务器mysqld组成,也可以在本地计算机或Internet上为其他客户端提供服务。

    mySQL使用socket进行通信。服务器侦听套接字以进行连接,并分叉新进程,为子进程提供套接字描述符以进行处理。当孩子完成处理时,它可以退出。

    有UNIX套接字和Internet套接字,具有不同的命名空间。在Linux上用C编程套接字的一个指南是sockets chapter of the The GNU C Library manual

    不等待I / O是分离进程的替代方法。这是在C中使用select()系统调用完成的,该调用允许进程等待一个或多个文件(包括套接字)上的事件或超时。 GNU C Library文档包括a no-wait I/O socket server example

    NodeJS是Javascript语言的服务器,使用无等待I / O编写为单线程服务器,并表明这些技术在现代系统中仍然相关。

    &#34;回调&#34;

      

    我假设当我输入myapp foo bar时无法让linux调用回调?

    <强>也许即可。但是值得努力可能是太多的工作。

    当您在&#34; Linux&#34;中键入myapp foo bar,而不是Linux时,您正在键入命令shell,这是一个在自己的进程中运行的程序,与所有内容分开其他

    因此,除非您想要的功能内置于命令shell中,否则通常无法在不启动新进程的情况下将该命令shell发送到其他程序。

    许多(但不是全部)Linux系统的默认命令shell是/bin/bash。要与监听来自bash的套接字的守护进程通信,我们需要bash中的套接字打开过程。而且,果然,它存在!

    可以在bash中收听套接字。这是守护进程的基础:

    来自:Simple Socket Server in Bash? answer by dtmilano

      问:我有一个简单的调试解决方案,可以将内容写入127.0.0.1:4444,我希望能够简单地从bash绑定一个端口并打印出来的所有内容。有一个简单的方法吗?

         

    答:

         

    $ exec 3&lt;&gt; /dev/tcp/127.0.0.1/4444

         

    $ cat&lt;&amp; 3

    还可以打开从bash到远程进程的套接字,即与守护进程通信:

    来自:TCP connection, bash only

    我们学习exec 5<>"/dev/tcp/${SERVER}/${PORT}"将TCP链接重定向到文件描述符5,用于输入和输出。

    并非所有bash程序都是使用TCP支持编译的。它显然依赖于Linux发行版。至少根据on this answer

    的评论William Pursell

    bash之外还有其他贝壳。许多炮弹都是在* nix时代发展起来的。 ksh Korn shell。 csh C-shell。 Bourne shell sh。灰壳。维基百科保持list of shells。而这些炮弹各有各的优缺点,并不完全兼容彼此的格式!

    快进约30年,现在还没有这么多共同使用。

    但这里存在一个重要特征:每个用户都可以选择自己的登录shell 。请参阅chsh命令。

    所以我要去的地方是,如果bash不支持你需要做的通信,你可以设置一个命令shell,可以在不打开新进程的情况下发送特殊消息。这可能会为您节省几毫秒的时间,而且通常不值得。但没有什么能阻止你。您甚至可以按https://stackoverflow.com/a/209670/103081中的建议设置ipython命令shell,python可以导入与您的专用守护进程进行套接字通信所需的大部分内容。

答案 1 :(得分:3)

您的帖子中存在太多劣质问题,因此无法在一个紧凑的回复中回答这些问题。此外,一些问题就像品味比较请求 - 我的意思是&#34;什么是最好的方式?&#34; - 这种问题通常不喜欢SO。尽管如此,我还是尝试提供至少基本的参考资料,你可以继续。

  

将消息发送到我的linux守护程序应用程序的最简单方法是什么?

除非你已经使用了一些提供这种方式的框架,否则就没有这种方法。守护进程太不同了。有些只需要一组简单的固定消息,有些需要复杂的重新配置和内部数据的即时修改。主要方法是:

  1. Unix信号实际上是提供受保护的最简单方式(只需简单的简化,只有相同的用户或超级用户可以发送它们),幂等(重复不得改变信号含义),非参数化消息;这样的消息集是非常有限的(Linux中约有50个免费使用的消息集)。它们是异步传递的,但可以转换为目标应用程序中的内部消息队列成员。它们的主要用途是简单的消息,因为&#34;优雅地停止&#34;,&#34;重读你的配置&#34;或&#34;打开调试消息&#34;。
  2. Unix域套接字是任何交互的基本IPC传输(除了共享内存更好的最快的)。它们允许数据报(如UDP),字节流(如TCP)和消息流(如SCTP或SPX)。监听套接字应在文件系统中用客户端已知的路径表示; Unix文件访问权限将规范对它的访问,或者您可以明确地检查凭据。实际上,任何协议都可以通过这样的套接字构建,但只有来自相同运行的操作系统的客户端才能连接它,即使从虚拟化案例中的主机操作系统,这些套接字也不会自动可见。
  3. 非管道式IPC:共享内存和信号量可用于高负载交互,但它们需要强大的使用规则。这种接口有两种版本(SysV和Posix)。
  4. Internet域套接字提供与Unix域套接字相同的传输,允许从任何远程客户端(不是在同一操作系统上)访问,但不自动提供访问检查,因此需要进行客户端身份验证。通常还需要传输保护(SSL / TLS等)。
  5. 通过套接字接口提供各种框架,这些框架实现了所需功能的某些部分,例如注册,端点发布,服务器搜索等。对于本地交互,现在从Dbus开始,Dbus是面向消息的,允许在公共OS空间或用户本地空间中使用命名服务器和类型消息。
  6. 去年开发了不同的全网消息传输(AMQP,ZeroMQ,Apache Kafka等)。它们专为在分布式网络中使用而设计,但通常没有任何身份验证。
  7. 自制守护进程的主要问题是您应明确附加任何这些接口,并提供监听,解码和处理传入消息的框架。如果你的应用程序已经是消息驱动的,你可以把它放到一个由设计消息驱动的环境中(Erlang,J2EE ......),除非你害怕重写另一种语言:)

      

    myapp foo bar是否可以调用回调而不是启动新进程?

    它与风格相关的问题比主要问题更多。您可以使用与长时间运行控制工具相同的方式命名控制工具。在实践中有这样的例子:SysV init(telinit只是便利名称),firefox(没有-no-remote它试图连接到已经运行的实例),但通常,首选单独的名称:

    • apachectl启动/停止/控制守护程序但守护程序名称为httpd;
    • rndc代表namedgdc代表gated等。

    如果一个守护进程二进制文件是一个非常胖的人,每次为一个小的控制消息启动它的成本太高,应该避免。但如果你真的想这样做,请确定两件事:

    • 除非找到正在运行的实例,否则是否希望它自动启动?
    • 你如何根据控制请求distingiush守护进程启动请求?

    如果您对这两个问题都有很好的答案,那么您无需担心。

      

    与守护进程通信的标准方法是什么?

    不,没有标准方式。有几种标准方法,见上文。人们应该根据确定的利弊选择一种方式。

      

    在/ var / run中粘贴PID并创建命名管道或套接字是我最合理的选择吗?

    再次,请参阅上文,但您知道,除非守护程序具有root权限,否则/ run(/ var / run)是不可写的。非root守护进程应使用完全另一个目录(例如〜/ run /用于其专用用户主目录)或提供可写子目录。

      

    我假设当我输入myapp foo bar时无法让linux调用回调?

    你再次要求&#34;回调&#34;我不明白它究竟代表什么。如果您的守护程序是在事件驱动的环境中使用命令式语言编写的,则应明确实现从其他进程接收的任何消息。对于Unix信号,您可以编写信号接收功能并配置进程以在输入信号上启动它们。对于套接字,您应创建套接字,为其提供已知地址,将其置于侦听模式并提供接受传入连接的代码,收集和解码消息等。仅对于已经事件驱动的环境,您可以使用标准方法。

    对于Erlang,这种远程控制通常使用gen_server:call()或analog实现为连接到守护程序节点和RPC请求。被调用的Erlang进程在通用代码中处理它,而不需要实现请求者是同一节点或另一个节点上的另一个进程的情况。

    有些框架已经在程序环境中实现了一些这样的需求;例如Dbus客户端库可以用它们

    的方式编写
    • 为Dbus套接字侦听创建一个单独的线程;
    • 接受传入的消息并调用您指定的回调,

    但这有其自身的缺点:

    • 回调在自己的线程中运行;您应提供适当的同步以避免数据损坏;
    • 信息速率很大,流量控制至少太粗糙,甚至不可能,守护进程可能会在实现总线连接之前提前溢出。

    总结一下,您最初的问题就像是&#34;我如何以有效的方式到达我朋友的家?&#34;最少的细节。如果你的朋友住在隔壁,你可以步行20米,或者你可以骑自行车,或者你需要打电话给出租车,或者你需要租一艘太空船到达月球的背面:)你应该反复缩小你的要求直到一个变体仍然存在。