提问人:shushuangyan 提问时间:7/7/2023 最后编辑:shushuangyan 更新时间:7/10/2023 访问量:58
使用 golang exec 时。命令或操作系统。使用 mysql 的 StartProcess
when use golang exec.Command or os.StartProcess with mysql
问:
我想制作一个可以通过 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))
}
答:
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赞
shushuangyan
7/7/2023
#2
我发现MySQL客户端打开了缓冲区,当我给出arg --unbuffered时,输出将发送到我的pumpStdout。 进度退出也可以通过添加 arg,--force 来修复。 所有这些都有效。 如果您有更好的解决方案,请告诉我,谢谢! Detial for mysql --help
-n, --unbuffered 每次查询后刷新缓冲区。
评论