Write to existing tcp socket over telnet/ssh in Go on Windows

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

Write to existing tcp socket over telnet/ssh in Go on Windows

问题

我正在尝试从另一个控制台/终端应用程序中的Go程序向屏幕写入/打印文本,这是一个从旧式公告板系统(BBS)启动的“门”程序。

BBS本身通过telnet连接运行在localhost:2323上。当启动我的程序时,BBS会自动将正确的套接字句柄作为参数添加进来,我可以使用Flag读取它(它是一个整数,例如236)。

显然,在Linux上,我只需使用fmt.Println("Hello World!")并使用os.Stdout... 但在Windows上,我需要以某种方式将Go程序的输出管道/重定向到提供的套接字。

这是我开始的函数:

func writeOut(fd int, buf []byte) bool {
    for len(buf) > 0 {
        n, err := syscall.Write(syscall.Handle(fd), buf)
        if err != nil {
            fmt.Println(err)
            return false
        }
        buf = buf[n:]
    }
    return true
}

从以下位置调用:

writeOut(socketInt, []byte("Writing to Windows socket..."))

返回的错误是:“参数不正确”。

我做错了什么,如何在Go中实现这个?

英文:

I am attempting to write/print text to the screen from a Go program launched from another console/terminal application--a "door" program that launches from an old-school Bulletin Board System (BBS).

The BBS itself runs over a telnet connection, localhost:2323. And when launching my program, the BBS automatically adds the correct socket handle as an argument, which I can then read using Flag (it's an integer, like 236).

Obviously, in Linux, I'd just use fmt.Println("Hello World!") using os.Stdout... But on Windows, I need to somehow pipe/redirect the Go program's output to the provided socket.

Here's the function I started with:

func writeOut(fd int, buf []byte) bool {
	for len(buf) > 0 {
		n, err := syscall.Write(syscall.Handle(fd), buf)
		if err != nil {
			fmt.Println(err)
			return false
		}
		buf = buf[n:]
	}
	return true
}

called from:

 writeOut(socketInt, []byte("Writing to Windows socket..."))

The error returned is: The parameter is incorrect

What am I doing wrong, and how would this be accomplished in Go?

答案1

得分: 2

你不能随意将文件或套接字句柄传递给另一个进程,除非该进程从你的进程继承了这些句柄。每个进程都有自己独特的句柄集。在POSIX中,继承套接字句柄是可能的(尽管不推荐),但在Windows中它们无法被继承(参见Are TCP SOCKET handles inheritable?)。

但是,当调用CreateProcess时,你可以将stdout重定向到TCP套接字,这样当程序被调用时,它确实可以通过fmt.Println将输出直接发送到套接字:

func serveDoor(conn *net.TCPConn, name string, args ...string) {
	defer conn.Close()

	cmd := exec.Command(name, args...)
	cmd.Stdin = conn
	cmd.Stdout = conn
	cmd.Stderr = conn

	err := cmd.Run()
	fmt.Println("door finished:", err)
}

完整代码片段

另一种解决方案是使用管道将输出发送到套接字。

英文:

You can't arbitrarily pass file or socket handles to another process that isn't inheriting them from your process in the first place. Each process has its own unique set of handles. In POSIX inheriting socket handles is possible (albeit not recommended) but in Windows they simply cannot be inherited (see Are TCP SOCKET handles inheritable?).

You can redirect stdout to a TCP socket when calling CreateProcess though, so that when invoked, your program can indeed fmt.Println to stdout and the output would go straight to the socket:

func serveDoor(conn *net.TCPConn, name string, args ...string) {
	defer conn.Close()

	cmd := exec.Command(name, args...)
	cmd.Stdin = conn
	cmd.Stdout = conn
	cmd.Stderr = conn

	err := cmd.Run()
	fmt.Println("door finished:", err)
}

(full gist)

Another solution is to use a pipe and pump it to the socket.

huangapple
  • 本文由 发表于 2022年2月26日 01:58:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/71269917.html
匿名

发表评论

匿名网友

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

确定