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,下回再说了!

none
最后修改于:2023年08月15日 14:03

评论已关闭