项目需要在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,下回再说了!