This commit is contained in:
Xargin
2016-10-05 13:42:01 +08:00
parent 5fd1e1d48f
commit f2df739842
6 changed files with 19 additions and 19 deletions

View File

@@ -29,11 +29,11 @@ func main() {
}
```
当用户关闭了标准输入主goroutine中的mustCopy函数调用将返回然后调用conn.Close()关闭读和写方向的网络连接。关闭网络接中的写方向的接将导致server程序收到一个文件end-of-file结束的信号。关闭网络接中读方向的接将导致后台goroutine的io.Copy函数调用返回一个“read from closed connection”“从关闭的接读”类似的错误因此我们临时移除了错误日志语句在练习8.3将会提供一个更好的解决方案。需要注意的是go语句调用了一个函数字面量这Go语言中启动goroutine常用的形式。
当用户关闭了标准输入主goroutine中的mustCopy函数调用将返回然后调用conn.Close()关闭读和写方向的网络连接。关闭网络接中的写方向的接将导致server程序收到一个文件end-of-file结束的信号。关闭网络接中读方向的接将导致后台goroutine的io.Copy函数调用返回一个“read from closed connection”“从关闭的接读”类似的错误因此我们临时移除了错误日志语句在练习8.3将会提供一个更好的解决方案。需要注意的是go语句调用了一个函数字面量这Go语言中启动goroutine常用的形式。
在后台goroutine返回之前它先打印一个日志信息然后向done对应的channel发送一个值。主goroutine在退出前先等待从done对应的channel接收一个值。因此总是可以在程序退出前正确输出“done”消息。
基于channels发送消息有两个重要方面。首先每个消息都有一个值但是有时候通讯的事实和发生的时刻也同样重要。当我们更希望强调通讯发生的时刻时我们将它称为**消息事件**。有些消息事件并不携带额外的信息它仅仅是用作两个goroutine之间的同步这时候我们可以用`struct{}`空结构体作为channels元素的类型虽然也可以使用bool或int类型实现同样的功能`done <- 1`语句也比`done <- struct{}{}`更短。
**练习 8.3** 在netcat3例子中conn虽然是一个interface类型的值但是其底层真实类型是`*net.TCPConn`代表一个TCP接。一个TCP接有读和写两个部分可以使用CloseRead和CloseWrite方法分别关闭它们。修改netcat3的主goroutine代码只关闭网络接中写的部分这样的话后台goroutine可以在标准输入被关闭后继续打印从reverb1服务器传回的数据。要在reverb2服务器也完成同样的功能是比较困难的参考**练习 8.4**。)
**练习 8.3** 在netcat3例子中conn虽然是一个interface类型的值但是其底层真实类型是`*net.TCPConn`代表一个TCP接。一个TCP接有读和写两个部分可以使用CloseRead和CloseWrite方法分别关闭它们。修改netcat3的主goroutine代码只关闭网络接中写的部分这样的话后台goroutine可以在标准输入被关闭后继续打印从reverb1服务器传回的数据。要在reverb2服务器也完成同样的功能是比较困难的参考**练习 8.4**。)