Golang Go语言中常规应该如何向已经运行的程序发送带参数的指令?

发布于 1周前 作者 zlyuanteng 来自 Go语言

想让程序在运行时通过外部命令(带参数)执行不同的函数方法。比如可执行程序是"imabin",imabin 已经运行中,在命令行“imabin add='xxx' host='xxx' port='xxx'”可以让已经运行的进程执行相应的函数,是不是应该这样操作?这样做是不是还要考虑重复启动和查找已经运行的进程的问题,有没有别的方式?

用信号的话,不可以带参数而且只有两个自定义信号。 用端口通信的话,是不是没必要?

大佬的常规做法是怎样?


Golang Go语言中常规应该如何向已经运行的程序发送带参数的指令?

更多关于Golang Go语言中常规应该如何向已经运行的程序发送带参数的指令?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

28 回复

搞个配置文件,配置监听端口或者 socket 或者 pid
再次运行的时候读取配置,检查相应的端口或者 socket ,然后向进程发送你的参数

更多关于Golang Go语言中常规应该如何向已经运行的程序发送带参数的指令?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢大佬,监听端口是为了做已运行的标记还是为了接收参数?“然后向进程发送你的参数”是用 tcp 或者 udp 向端口发参数吗?这是常规做法吗?

不同操作系统有自己的互斥体试下,程序启动时候检查这个互斥体,然后做去重处理。然后检查到已被持有后,转发命令行参数到已运行进程,已运行进程可用使用 TCP/进程管道/文件监听等多种方式来获取刚刚启动程序传递的参数。没有什么常规不常规。要看你的实际需求。有很多方法可用做到你需要的这种操作。

互斥体实现

哪种方法最常规不知道,但最简单的肯定是直接用官方的 rpc 包: https://pkg.go.dev/net/rpc
不同实例就监听不同端口

明显是个 X-Y problem ,请说出你的原始需求。

docker 和 caddy 都是监听一个 unix socket 通信

常见的 daemon+cli 模式呗,比如 docker

这要涉及到进程间通讯
无非就是 tcp 或者 socket 这几种

端口和 socket, pid 都可以用于标识进程已运行

都用 go 了,起个服务,可扩展性更高。

搞个 unix domain socket 完事。

要是只用一个 mgr 管理的话,甚至可以直接 stdin stdout stderr 结合实现。。

避免重复启动和查找已运行进程用 pid file 实现(即使 pid file 存在最好也要做几次检查,看看 pid file 里面的 pid 到底是否存在,避免意外结束导致 pid file 没有正确释放),非常追求唯一性的话可以考虑搞一下其他类型的锁来辅助。

如果直接带参跑新进程来做数据交换的话,不灵活,也不好改。


对,就是想实现像 docker 那样“docker+命令+参数”这种操作。请问大概实现方式是啥我去搜搜。


感谢老哥,我去查查。

docker 是 C/S 架构

你用的 docker + 命令 + 参数,docker 其实是客户端,用它来生成参数向 dockerd 这个进程发请求。dockerd 监听在本地 socks 文件上,可以为它配置权限属性,避免非授权访问…

所有功能上的事儿都是 dockerd 去完成的,比如 docker pull ,是 dockerd 在 pull…

====
当然你也可以像 hashicorp vault 那样,一个可执行程序,根据参数不同,既当 server 又当 client

前面说了那么多基于 rpc 通讯的方案,再说两个基于信号、文件监听的方案
1 、用 notify 监听配置文件的变动,执行对应动作
2 、监听指定 signal ,执行对应动作,动作里面可以包括读指定文件

试试 unix socket ?
我这个库封装了 websocket 服务端和客户端, 支持 unix socket 作为传输层
https://github.com/lxzan/gws

经典八股文之《进程间的通信方式》 , 里面随便挑一种就行.

inotify 的话有竞争情况
下发多个指令的时候,发指令和收指令方的节奏不容易协调

signal 的信息量太简略了

go 可以动态解析配置文件啊,监测到配置文件修改则重新读取,解析参数

#18 他的意思是把要执行的动作放到文件里,通过 signal 让正在运行的进程去读一下,然后执行。这种在频率不高的情况下可行,包括通过 signal 重读配置文件都可以,kill -HUP 经常用来干这事儿。但其实整套实现方案还是得根据具体情况进行选择,signal 重新初始化+旧子进程优雅退出,还是 socket/fifo 的方式发命令。另:notify 监听文件改变的方式在生产线上不可取,监听到事件到执行命令之间需要有个相对严格的验证文件正确性的过程,文件改变即执行的方式不容易做到。

正在看这个

哈哈哈,一看就是琢磨过干过这事的人

inotify 其实也可以校验正确性再加载,这倒不是问题

问题在于:发指令方如用“覆盖命令文件”的方式发了多次指令,但被指令方也许只读了一次配置文件,从而丢失了中间的其他指令;如果选用往命令文件内 append 内容的方式,又涉及到:被指令方应该从上次记忆的位置开始读文件、旧文件是否应该删除以节省空间、rotate 之后需要从头开始读之类的破事。虽然最终也可能达到正确,但是开发者的时间都浪费掉了


fifo ,多个指令一起发过来,存在打开文件冲突的问题

listen socket+多个 accept 的方式是相对靠谱的

#24 对,监控文件改动就去执行的方式,缺点就是缺乏一个明确的信号,容易漏,容易出错误(比如,如果不知道需要把所有指令一次性写入的话,有可能会一行甚至半行式的增加文件内容)导致非预期的结果。



看大佬对话受益匪浅,分析了一下自己的需求场景,多用户同时访问的机率为 0 ,用户只有我自己,所以我选修改配置文件后-HUP 。

mq:没错正是在下!

在Go语言中,向已经运行的程序发送带参数的指令通常涉及进程间通信(IPC)机制。这里有几种常见的方法可以实现这一点:

  1. 命令行参数与重启: 如果程序支持,可以在启动时通过命令行参数传递指令。这要求程序能够在接收到新参数后重新启动或重新加载配置。

  2. 使用信号: Unix系统上的信号(如SIGINT, SIGUSR1等)可以用来通知程序某些事件的发生,但信号本身不携带参数。可以通过信号触发程序读取配置文件或环境变量来获取参数。

  3. 网络通信: 使用TCP/UDP套接字或HTTP协议,程序可以作为服务器监听特定端口,接收来自客户端的指令和数据。这种方法灵活且功能强大,适用于需要实时通信的场景。

  4. 文件系统: 程序可以定期检查某个文件或目录的变化,以读取新的指令或参数。例如,可以通过写入文件来传递参数,程序轮询文件内容以获取更新。

  5. 消息队列或管道: 使用消息队列系统(如RabbitMQ)或Unix管道,可以实现更复杂的进程间通信。这些机制允许发送带有详细参数和数据的消息。

选择哪种方法取决于具体需求,如实时性、复杂度、安全性等因素。对于大多数应用场景,网络通信(特别是HTTP)因其灵活性和易用性而成为首选。设计时应考虑程序的架构和预期的通信模式,以选择最合适的IPC机制。

回到顶部