admin管理员组

文章数量:1333690

The child process is not exiting when I issue the exit command and the TCP server returns the original command with output. I have a simple Golang TCP server like the one below

package main

import (
    "fmt"
    "net"
    "os"
    "os/exec"
)

func handleConn(conn net.Conn) {
    defer conn.Close()

    cmd := exec.Command("powershell.exe")

    cmd.Stdin = conn
    cmd.Stdout = conn
    cmd.Stderr = conn

    if err := cmd.Start(); err != nil {
        panic(err)
    }

    if err := cmd.Wait(); err != nil {
        panic(err)
    }

    fmt.Fprintf(os.Stderr, "Connection closed\n")
}

func main() {
    // create listening socket
    ln, err := net.Listen("tcp", ":8080")

    if err != nil {
        fmt.Fprintf(os.Stderr, "Error Occured: %s", err.Error())
        return
    }

    // below line will run when main returns
    defer ln.Close()

    // accept connections one by one
    for {
        // accept new connection
        conn, err := ln.Accept()

        if err != nil {
            fmt.Fprintf(os.Stderr, "Error accepting connection: %s\n", err.Error())
            continue
        }

        go handleConn(conn)
    }

}

Then I try to connect it using socat like below,

socat tcp4:127.0.0.1:8080 -

But every time, I pass something, the TCP server echoes the command with the output like below,

And also when I pass the exit command, the child process is not exiting. I had to press ctrl+c then it closes the TCP connection and then the child process exits.

I am using Windows.

The child process is not exiting when I issue the exit command and the TCP server returns the original command with output. I have a simple Golang TCP server like the one below

package main

import (
    "fmt"
    "net"
    "os"
    "os/exec"
)

func handleConn(conn net.Conn) {
    defer conn.Close()

    cmd := exec.Command("powershell.exe")

    cmd.Stdin = conn
    cmd.Stdout = conn
    cmd.Stderr = conn

    if err := cmd.Start(); err != nil {
        panic(err)
    }

    if err := cmd.Wait(); err != nil {
        panic(err)
    }

    fmt.Fprintf(os.Stderr, "Connection closed\n")
}

func main() {
    // create listening socket
    ln, err := net.Listen("tcp", ":8080")

    if err != nil {
        fmt.Fprintf(os.Stderr, "Error Occured: %s", err.Error())
        return
    }

    // below line will run when main returns
    defer ln.Close()

    // accept connections one by one
    for {
        // accept new connection
        conn, err := ln.Accept()

        if err != nil {
            fmt.Fprintf(os.Stderr, "Error accepting connection: %s\n", err.Error())
            continue
        }

        go handleConn(conn)
    }

}

Then I try to connect it using socat like below,

socat tcp4:127.0.0.1:8080 -

But every time, I pass something, the TCP server echoes the command with the output like below,

And also when I pass the exit command, the child process is not exiting. I had to press ctrl+c then it closes the TCP connection and then the child process exits.

I am using Windows.

Share Improve this question edited Nov 21, 2024 at 9:03 PSKP asked Nov 20, 2024 at 18:01 PSKPPSKP 1,37417 silver badges38 bronze badges 2
  • You defer conn.Close() which will happen after Wait, but Wait can't return until the connection closes. – Mr_Pink Commented Nov 20, 2024 at 18:05
  • But when I pass exit, the child process should exit. – PSKP Commented Nov 21, 2024 at 7:49
Add a comment  | 

1 Answer 1

Reset to default 0

The truth is that they recommend you use Pipe, something like this:

package main

import (
    "fmt"
    "io"
    "net"
    "os"
    "os/exec"
)

func handleConn(conn net.Conn) {
    defer conn.Close()

    // The command to run the terminal in my case is /bin/bash is Linux
    // cmd := exec.Command("/bin/bash")
    // you case use this:
    cmd := exec.Command("powershell.exe")

    // Set the stdin, stdout, stderr of the command to the connection
    stdIn, err := cmd.StdinPipe()
    if err != nil {
        panic(err)
    }

    stdOut, err := cmd.StdoutPipe()
    if err != nil {
        panic(err)
    }

    stdErr, err := cmd.StderrPipe()
    if err != nil {
        panic(err)
    }

    // Read from the connection and write to the stdin of the command
    go func() {
        for {
            line := make([]byte, 1024)
            l, _ := conn.Read(line)
            //windows remove echo
            for i := 0; i < l; i++ {
                conn.Write([]byte("\b"))
            }

            stdIn.Write(line[:l])
        }
    }()

    go func() {
        buf := make([]byte, 1024)
        for {
            n, err := stdOut.Read(buf)
            if err == io.EOF {
                conn.Write([]byte("Terminal closed\n"))
                os.Stdout.Write([]byte("connection from " + conn.RemoteAddr().String() + " Terminal closed\n"))
                break
            }
            conn.Write(buf[:n])
        }
    }()

    go func() {
        buf := make([]byte, 1024)
        for {
            n, _ := stdErr.Read(buf)
            conn.Write(buf[:n])
        }
    }()

    if err := cmd.Run(); err != nil {
        panic(err)
    }
    // In this point the command has finished and the connection is closed
    // if you want to keep the connection open you can do something else
    // example:
    //conn.Write([]byte("other text to send \n"))

}

func main() {
    // create listening socket
    ln, err := net.Listen("tcp", ":8080")

    if err != nil {
        fmt.Fprintf(os.Stderr, "Error Occured: %s", err.Error())
        return
    }

    // below line will run when main returns
    defer ln.Close()

    // accept connections one by one
    for {
        // accept new connection
        conn, err := ln.Accept()

        if err != nil {
            fmt.Fprintf(os.Stderr, "Error accepting connection: %s\n", err.Error())
            continue
        }

        go handleConn(conn)
    }

}

本文标签: