英文:
How to perform socket activation, passing a socket to a child proc as stdin/out, in golang?
问题
我有一个通过systemd socket激活运行的C程序。Systemd监听一个端口,当有TCP连接进来时,应用程序就会启动,并且它会将stdin/stdout 完全当作一个套接字来处理(例如:setsockopt等)。
我正在尝试用一个小的启动程序在Go中模拟这种行为。它只需要告诉它要监听的端口和在连接建立时要运行的命令(不涉及其他高级systemd功能)。
我遇到的问题是,我似乎无法将连接作为套接字传递给stdin/out。将TCPConn传递给Cmd
的Stdin
和Stdout
并没有起作用(C程序在setsockopts上出错)。
cmd := exec.Cmd{
Path: cmds,
Args: args,
Stdin: conn,
Stdout: conn,
Stderr: os.Stderr,
}
err = cmd.Run()
我看到了一篇关于如何在C中使用dup(2)
和fork来做类似事情的文章,但是:
- 它是fork而不是exec另一个子进程
- 我不完全理解套接字fd是如何被复制而不是
client
接受的连接
在Golang中有没有办法做类似的事情?
附加信息
套接字文件大致如下:
[Unit]
Description=soc activated program
[Socket]
ListenStream=0.0.0.0:10101
Accept=yes
[Install]
WantedBy=sockets.target
相应的单元文件如下:
[Unit]
Description=My Program
[Service]
Type=simple
ExecStart=/usr/bin/myprog -N
StandardInput=socket
StandardOutput=socket
StandardError=journal
TimeoutStopSec=5
KillMode=process
[Install]
WantedBy=multi-user.target
英文:
I have a C program that runs via systemd socket activation. Systemd listens on a port and when a TCP connections comes in, then the application is launched and it treats stdin/stdout exactly like a socket (IE: setsockopt, etc) .
I am trying to mimic this behavior with a small launching program in go. It will just be told what port to listen on and what command to run when a connection is made to it (none of the other advanced systemd features).
The problem I am having is that I don't seem to be able to pass the connection as a socket to stdin/out. Passing the TCPConn to Stdin
and Stdout
of the Cmd
did not work (the C program errored on setsockopts).
cmd := exec.Cmd{
Path: cmds,
Args: args,
Stdin: conn.,
Stdout: conn,
Stderr: os.Stderr,
}
err = cmd.Run()
I saw an article on how to do something like this in C using dup(2)
and fork, but
- it is forking not exec-ing another child process
- I don't entirely understand with the socket fd is being duplicated and not the
client
accepted connection
Is there any way to do something like this in Golang?
aditional info
the socket file looks roughly like
[Unit]
Description=soc activated program
[Socket]
ListenStream=0.0.0.0:10101
Accept=yes
[Install]
WantedBy=sockets.target
and corresponding unit file looks like:
[Unit]
Description=My Program
[Service]
Type=simple
ExecStart=/usr/bin/myprog -N
StandardInput=socket
StandardOutput=socket
StandardError=journal
TimeoutStopSec=5
KillMode=process
[Install]
WantedBy=multi-user.target
答案1
得分: 1
使用连接的file:
f, err := conn.File()
if err != nil { /* TODO 处理错误 */ }
defer f.Close()
cmd := exec.Cmd{
Path: cmds,
Args: args,
Stdin: f,
Stdout: f,
Stderr: os.Stderr,
}
err = cmd.Run()
英文:
Use the connections's file:
f, err := conn.File()
if err != nil { /* TODO handle error */}
defer f.Close()
cmd := exec.Cmd{
Path: cmds,
Args: args,
Stdin: f,
Stdout: f,
Stderr: os.Stderr,
}
err = cmd.Run()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论