Golang实现windows两个应用程序进程间通信
warning:
这篇文章距离上次修改已过466天,其中的内容可能已经有所变动。
Golang实现windows两个应用程序进程间通信
一、 需求
项目需要在windows中由A服务启动B.exe,当B程序处理完任务后,将数据返回给A。由于需要考虑兼容性问题,不能用socket相关通信协议。
二、思路
在windows中要实现进程间通信,可以用的方式有:共享内存、socket、基于win32的消息通信(sendmessage)以及管道通信等。刚开始用的是通过临时文件来传递消息,即B程序将处理结果写到tmp.file中,服务A 隔xx秒去读取tmp.file。这个方法在项目中测试了没啥大问题,但是实在是非常Low。于决定采用其它方式实现,测试了共享内存来进行通信,发现只是比临时文件的方式好一点点,本质并没什么大的变化。再测试调用win32的api来sendmessage,发现这个api是在winform中才起作用,在service中没找到对应的消息处理函数,最终只能考虑采用道通信的方式。
三、实现
Golang实现windows的管道通信,可以采用go-winio这个包,地址:https://github.com/microsoft/go-winio/blob/main/pipe.go
。官方还比较贴心的给出了pipe_test.go这个使用样例,但是我看得很晕,测试也没生效。服务端监听是成功了,客户端也能连接上,就是怎么也收不到客户端发来的消息。google了一番,复制粘贴来的代码也没法用,需要调整下客户端的实现。以下是可以CV的源码:
- 服务端
package utils
import (
"io"
"log"
"net"
"github.com/Microsoft/go-winio"
)
func handleClient(c net.Conn) {
defer c.Close()
log.Printf("Client connected [%s]", c.RemoteAddr().Network())
buf := make([]byte, 512)
for {
n, err := c.Read(buf)
if err != nil {
if err != io.EOF {
log.Printf("read error: %v\n", err)
}
break
}
str := string(buf[:n])
log.Printf("read %d bytes: %q\n", n, str)
}
log.Println("Client disconnected")
}
func TestServerNN() {
pipePath := `\\.\pipe\mypipename`
l, err := winio.ListenPipe(pipePath, nil)
if err != nil {
log.Fatal("listen error:", err)
}
defer l.Close()
log.Printf("Server listening op pipe %v\n", pipePath)
for {
conn, err := l.Accept()
if err != nil {
log.Fatal("accept error:", err)
}
go handleClient(conn)
}
}
客户端
package utils import ( "log" "sync" "time" "github.com/Microsoft/go-winio" ) func TestClientNN() { pipePath := `\\.\pipe\mypipename` f, err := winio.DialPipe(pipePath, nil) if err != nil { log.Fatalf("error opening pipe: %v", err) } defer f.Close() log.Println("conn ok>>", f.RemoteAddr().String(), "network>>", f.RemoteAddr().Network()) var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() for i := 0; i < 50; i++ { n, err := f.Write([]byte("message from client!")) if err != nil { log.Fatalf("write error: %v", err) } log.Println(i, "<<wrote:", n) time.Sleep(2 * time.Second) } }() wg.Wait() // ret := f.SetWriteDeadline(time.Now().Add(20 * time.Second)) log.Printf("ret is >>%v", wg) }
四、别高兴太早
上述代码能跑起来了,但有Bug,下回再说了!
评论已关闭