How to perform socket activation, passing a socket to a child proc as stdin/out, in golang?

huangapple go评论78阅读模式
英文:

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传递给CmdStdinStdout并没有起作用(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()

huangapple
  • 本文由 发表于 2021年11月10日 04:48:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/69904891.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定