我正在尝试使用libchan库通过类似go channel的传输在机器之间发送消息。
根据我收集到的信息,大概是这样的:
Pipe
的libchan通道,通过该通道发送响应。Pipe
发送响应。这是我的困惑点。为了使通道在两台计算机之间持久存在,它们必须共享内存或至少共享连接它们两者的抽象。从我对libchan代码库的迷惑中,我不知道这怎么可能。
以下是仓库中示例的摘录:
// client
receiver, remoteSender := libchan.Pipe()
command := &RemoteCommand{
Cmd: os.Args[1],
Args: os.Args[2:],
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
StatusChan: remoteSender,
}
err = sender.Send(command)
if err != nil {
log.Fatal(err)
}
err = receiver.Receive(response)
if err != nil {
log.Fatal(err)
}
os.Exit(response.Status)
和服务器:
// server
t := spdy.NewTransport(p)
go func() {
for {
receiver, err := t.WaitReceiveChannel()
if err != nil {
log.Print("receiver error")
log.Print(err)
break
}
log.Print("about to spawn receive proc")
go func() {
for {
command := &RemoteReceivedCommand{}
err := receiver.Receive(command)
returnResult := &CommandResponse{}
if res != nil {
if exiterr, ok := res.(*exec.ExitError); ok {
returnResult.Status = exiterr.Sys().
(syscall.WaitStatus).ExitStatus()
} else {
log.Print("res")
log.Print(res)
returnResult.Status = 10
}
}
err = command.StatusChan.Send(returnResult)
我要磨练的重点在这里:
libchan.Pipe()
根据来源,这将返回一个频道。一个引用保留在客户端上,而另一个则发送到服务器。然后使用此通道将值从后者传递到前者。实际上这是如何工作的?
答案 0 :(得分:0)
首先,很高兴知道Pipe()所做的所有事情都是建立一个通道并返回内存中的发送者/接收者对。
来自inmem.go
:
// Pipe returns an inmemory Sender/Receiver pair.
func Pipe() (Receiver, Sender) {
c := make(chan interface{})
return pReceiver(c), pSender(c)
}
然后,您可以在inmem_test.go
中查看一个简单的端到端示例。
This struct相当于演示中的RemoteCommand
。
type InMemMessage struct {
Data string
Stream io.ReadWriteCloser
Ret Sender
}
在TestInmemRetPipe()
中,创建了一个简单的客户端和服务器。
The client使用Pipe()创建本地发送者/接收者对,而the server仅在InMemMessage
结构中使用libchan.Sender
interface。
请注意,客户端和服务器是分别接收发送方或接收方作为参数的函数。在下一个代码片段中对此有更多的了解。
func TestInmemRetPipe(t *testing.T) {
client := func(t *testing.T, w Sender) {
ret, retPipe := Pipe()
message := &InMemMessage{Data: "hello", Ret: retPipe}
err := w.Send(message)
if err != nil {
t.Fatal(err)
}
msg := &InMemMessage{}
err = ret.Receive(msg)
if err != nil {
t.Fatal(err)
}
if msg.Data != "this better not crash" {
t.Fatalf("%#v", msg)
}
}
server := func(t *testing.T, r Receiver) {
msg := &InMemMessage{}
err := r.Receive(msg)
if err != nil {
t.Fatal(err)
}
if msg.Data != "hello" {
t.Fatalf("Wrong message:\n\tExpected: %s\n\tActual: %s", "hello", msg.Data)
}
if msg.Ret == nil {
t.Fatal("Message Ret is nil")
}
message := &InMemMessage{Data: "this better not crash"}
if err := msg.Ret.Send(message); err != nil {
t.Fatal(err)
}
}
SpawnPipeTestRoutines(t, client, server)
}
SpawnPipeTestRoutines()
执行客户端和服务器功能。在此功能中,通过Pipe()
实例化了另一个发送方/接收方空气。
在演示应用程序中,Pipe()
在此处执行的功能(即促进客户端和服务器实例之间的通信)由网络通信处理。
func SpawnPipeTestRoutines(t *testing.T, s SendTestRoutine, r ReceiveTestRoutine) {
end1 := make(chan bool)
end2 := make(chan bool)
receiver, sender := Pipe()
go func() {
defer close(end1)
s(t, sender)
err := sender.Close()
if err != nil {
t.Fatalf("Error closing sender: %s", err)
}
}()
go func() {
defer close(end2)
r(t, receiver)
}()
...
在演示应用程序中,通过在客户端和Transport.NewSendChannel()上分别调用libchan.Sender
和libchan.Receiver
来调用Transport.WaitReceiveChannel()来促进通信。这些libchan实例通过网络来处理“管道”。
从client.go:
sender, err := transport.NewSendChannel()
...
err = sender.Send(command)
从server.go:
receiver, err := t.WaitReceiveChannel()
...
err := receiver.Receive(command)
在两种情况下,都必须先完成必备的传输配置(即绑定到套接字,使用TLS等)。
the spdy library being used is part of the libchan distribution可能也值得一提,因此它提供了libchan基元。