使用 golang exec 时。命令或操作系统。使用 mysql 的 StartProcess

when use golang exec.Command or os.StartProcess with mysql

提问人:shushuangyan 提问时间:7/7/2023 最后编辑:shushuangyan 更新时间:7/10/2023 访问量:58

问:

我想制作一个可以通过 websocket 执行 sql 或命令的 golang 应用程序,我使用包“github.com/gorilla/websocket”、“os/exec”、“os”、

我已经完成了 redis-cli 和 mongoshell。 但是当我使用MySQL客户端连接MySQL时,我无法收到来自progress的消息,但是当我仅将progress(mysql client)输出设置为stdout时,它可以显示。当错误sql发送到进度时,它由未知关闭。 它可以通过 github.com/gorilla/websocket 的例子反复出现,https://github.com/gorilla/websocket/blob/master/examples/command/main.go

这是我的代码

package main

import (
    "flag"
    "fmt"
    "io"
    "log"
    "net/http"
    "os/exec"
    "time"

    "github.com/gorilla/websocket"
)

var (
    addr    = flag.String("addr", "127.0.0.1:8080", "http service address")
)

const (
    // Time allowed to write a message to the peer.
    writeWait = 10 * time.Second

    // Maximum message size allowed from peer.
    maxMessageSize = 8192

    // Time allowed to read the next pong message from the peer.
    pongWait = 20 * time.Second

    // Send pings to peer with this period. Must be less than pongWait.
    pingPeriod = (pongWait * 9) / 10


)

func ping(ws *websocket.Conn, done chan struct{}) {
    ticker := time.NewTicker(pingPeriod)
    defer ticker.Stop()
    for {
        select {
        case <-ticker.C:
            if err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(writeWait)); err != nil {
                log.Println("ping:", err)
            }
            done <- struct{}{}
        case <-done:
            return
        }
    }
}

func pumpStdin(ws *websocket.Conn, w io.Writer) {
    defer ws.Close()
    ws.SetReadLimit(maxMessageSize)
    ws.SetReadDeadline(time.Now().Add(pongWait))
    ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
    for {
        _, message, err := ws.ReadMessage()
        if err != nil {
            break
        }
        message = append(message, '\n')
        if _, err := w.Write(message); err != nil {
            break
        }
    }
}

func pumpStdout(ws *websocket.Conn, r io.ReadCloser, done chan struct{}) {
    for {
        x := make([]byte, 1024)
        n, err := r.Read(x)
        if err != nil {
            fmt.Println(err)
        }
        fmt.Println(string(x[:n]))
    }
}

var upgrader = websocket.Upgrader{}

func serveWs(w http.ResponseWriter, r *http.Request) {
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Println("upgrade:", err)
        return
    }

    defer ws.Close()
    
    stopchan := make(chan struct{})
    cmd := exec.Command("/usr/bin/mysql", "-h127.0.0.1", "-ppassword", "-P3306", "-uroot")
    
    cmdin, err := cmd.StdinPipe()
    if err != nil {
        fmt.Println(err)
    }
    cmdout, err := cmd.StdoutPipe()
    if err!=nil{
        fmt.Println(err)
    }

    if err := cmd.Start(); err != nil {
        log.Fatal(err)
    }
    go ping(ws, stopchan)
    go pumpStdout(ws, cmdout, stopchan)
    pumpStdin(ws, cmdin)
    if err = cmd.Wait(); err != nil {
        fmt.Println(err)
    }

}

func main() {
    flag.Parse()
    http.HandleFunc("/ws", serveWs)
    log.Fatal(http.ListenAndServe(*addr, nil))
}


MySQL 的Linux Go

评论


答:

0赞 Divyaraj Chudasama 7/7/2023 #1
func pumpStdout(ws *websocket.Conn, r io.ReadCloser, done chan struct{}) {
defer ws.Close()
defer r.Close()

buf := make([]byte, 1024)
for {
    n, err := r.Read(buf)
    if err != nil {
        fmt.Println(err)
        break
    }

    output := buf[:n]
    if _, err := ws.Write(output); err != nil {
        fmt.Println(err)
        break
    }
    
    // Flush the output buffer
    if fw, ok := ws.UnderlyingConn().(*net.TCPConn); ok {
        if err := fw.SetWriteDeadline(time.Now().Add(writeWait)); err != nil {
            fmt.Println(err)
            break
        }
        if err := fw.Flush(); err != nil {
            fmt.Println(err)
            break
        }
    }
}

done <- struct{}{}

}

评论

0赞 shushuangyan 7/7/2023
谢谢,结构网。TCPConn 没有 Flush 方法,我通过添加参数对其进行了重新保护。
0赞 shushuangyan 7/7/2023
它是由缓冲区引起的。
0赞 Community 7/9/2023
正如目前所写的那样,你的答案尚不清楚。请编辑以添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。您可以在帮助中心找到有关如何写出好答案的更多信息。
0赞 shushuangyan 7/7/2023 #2

我发现MySQL客户端打开了缓冲区,当我给出arg --unbuffered时,输出将发送到我的pumpStdout。 进度退出也可以通过添加 arg,--force 来修复。 所有这些都有效。 如果您有更好的解决方案,请告诉我,谢谢! Detial for mysql --help

-n, --unbuffered 每次查询后刷新缓冲区。

评论

0赞 Community 7/9/2023
您的答案可以通过其他支持信息进行改进。请编辑以添加更多详细信息,例如引文或文档,以便其他人可以确认您的答案是正确的。您可以在帮助中心找到有关如何写出好答案的更多信息。