NewEndpoint()函数是Endpoint的工厂函数。它只对handler映射进行了初始化。为了简化问题,假设我们的终端监听的端口好是固定的。
Endpoint类型声明了几个方法:
AddHandleFunc(): 使用互斥锁为handler属性安全添加处理特定类型命令的处理器函数。 Listen(): 对终端端口的所有接口启动监听。 在调用Listen之前,至少要通过AddHandleFunc()注册一个handler函数。 HandleMessages(): 将连接用bufio包装起来,然后分两步读取,首先读取命令加换行,我们得到命令名字。 然后通过handler获取注册的该命令对应的处理器函数, 然后调度这个函数来执行数据读取和解析。.注意:上面如何使用动态函数的。 根据命令名查找具体函数,然后这个具体函数赋值给handleCommand, 其实这个变量类型为HandleFunc类型, 即前面声明的处理器函数类型。
Endpoint的Listen方法调用之前需要先至少注册一个处理器函数。因此我们下面定义两个类型的处理器函数: handleStrings和handleGob。
handleStrings()函数接收和处理我们即时协议中只发送字符串数据的处理器函数。handleGob()函数是接收并处理发送的gob数据的复杂结构体。handleGob稍微复杂一点,除了读取数据外,我们海需要解码数据。
我们可以看到连续两次使用rw.ReadString('n'), 读取字符串,遇到换行停止, 将读到的内容保存到字符串中。注意这个字符串是包含末尾换行的。
另外对于普通字符串数据来说,我们直接用bufio包装连接后的ReadString来读取。而对于复杂的gob结构体来说,我们使用gob来解码数据。
func handleStrings(rw *bufio.ReadWriter) {
log.Print("Receive STRING message:")
s, err := rw.ReadString('n')
if err != nil {
log.Println("Cannot read from connection.n", err)
}
s = strings.Trim(s, "n ")
log.Println(s)
-, err = rw.WriteString("Thank you.n")
if err != nil {
log.Println("Cannot write to connection.n", err)
}
err = rw.Flush()
if err != nil {
log.Println("Flush failed.", err)
}
}
func handleGob(rw *bufio.ReadWriter) {
log.Print("Receive GOB data:")
var data complexData
dec := gob.NewDecoder(rw)
err := dec.Decode(&data)
if err != nil {
log.Println("Error decoding GOB data:", err)
return
}
log.Printf("Outer complexData struct: n%#vn", data)
log.Printf("Inner complexData struct: n%#vn", data.C)
}
客户端和服务端函数
一切就绪,我们可以准备我们的客户端和服务端函数了。
客户端函数连接到服务器并发送STRING和GOB请求。
服务端开始监听请求并触发恰当的处理器。
// 当应用程序使用-connect=ip地址的时候被调用
func client(ip string) error {
testStruct := complexData{
N: 23,
S: "string data",
M: map[string]int{"one": 1, "two": 2, "three": 3},
P: []byte("abc"),
C: &complexData{
N: 256,
S: "Recursive structs? Piece of cake!",
M: Map[string]int{"01": "10": 2, "11": 3},
},
}
rw, err := Open(ip + Port)
if err != nil {
return errors.Wrap(err, "Client: Failed to open connection to " + ip + Port)
}
log.Println("Send the string request.")
n, err := rw.WriteString("STRINGn")
if err != nil {
return errors.Wrap(err, "Could not send the STRING request (" + strconv.Itoa(n) + " bytes written)")
}
// 发送STRING请求。发送请求名并发送数据。
log.Println("Send the string request.")
n, err = rw.WriteString("Additional data.n")
if err != nil {
return errors.Wrap(err, "Could not send additional STRING data (" + strconv.Itoa(n) + " bytes written)")
}
log.Println("Flush the buffer.")
err = rw.Flush()
if err != nil {
return errors.Wrap(err, "Flush failed.")
}
// 读取响应
log.Println("Read the reply.")
response, err := rw.ReadString('n')
if err != nil {
return errors.Wrap(err, "Client: Failed to read the reply: '" + response + "'")
}
log.Println("STRING request: got a response:", response)
// 发送GOB请求。 创建一个encoder直接将它转换为rw.Send的请求名。发送GOB
log.Println("Send a struct as GOB:")
log.Printf("Outer complexData struct: n%#vn", testStruct)
log.Printf("Inner complexData struct: n%#vn", testStruct.C)
enc := gob.NewDecoder(rw)
n, err = rw.WriteString("GOBn")
if err != nil {
return errors.Wrap(err, "Could not write GOB data (" + strconv.Itoa(n) + " bytes written)")
}
err = enc.Encode(testStruct)
if err != nil {
return errors.Wrap(err, "Encode failed for struct: %#v", testStruct)
}
err = rw.Flush()
if err != nil {
return errors.Wrap(err, "Flush failed.")
}
return nil
}









