diff --git a/eBook/15.1.md b/eBook/15.1.md index 353f8ac..d06c495 100644 --- a/eBook/15.1.md +++ b/eBook/15.1.md @@ -5,6 +5,7 @@ 服务器代码,单独的一个文件: 示例 15.1 [server.go](examples/chapter_15/server.go) + ```go package main @@ -51,6 +52,7 @@ func doServerStuff(conn net.Conn) { 客户端代码写在另外一个文件client.go中: 示例 15.2 [client.go](examples/chapter_15/client.go) + ```go package main @@ -107,6 +109,7 @@ func main() { 然后开启2个或者3个独立的控制台窗口,然后分别输入client回车启动客户端程序 以下是服务器的输出: + ``` Starting the Server ... Received data: IVO says: Hi Server, what's up ? @@ -114,6 +117,7 @@ Received data: CHRIS says: Are you busy server ? Received data: MARC says: Don't forget our appointment tomorrow ! ``` 当客户端输入 Q 并结束程序时,服务器会输出以下信息: + ``` Error reading WSARecv tcp 127.0.0.1:50000: The specified network name is no longer available. ``` @@ -122,6 +126,7 @@ Error reading WSARecv tcp 127.0.0.1:50000: The specified network name is no long 下边这个示例先使用TCP协议连接远程80端口,然后使用UDP协议连接,最后使用TCP协议连接IPv6类型的地址: 示例 15.3 [dial.go](examples/chapter_15/dial.go) + ```go // make a connection with www.example.org: package main @@ -151,6 +156,7 @@ func checkConnection(conn net.Conn, err error) { 下边也是一个使用net包从socket中打开,写入,读取数据的例子: 示例 15.4 [socket.go](examples/chapter_15/socket.go) + ```go package main @@ -183,7 +189,10 @@ func main() { con.Close() } ``` -**练习 15.1** 编写新版本的客户端和服务器([client1.go](exercises/chapter_15/client1.go) / [server1.go](exercises/chapter_15/server1.go)): +**练习 15.1** + +编写新版本的客户端和服务器([client1.go](exercises/chapter_15/client1.go) / [server1.go](exercises/chapter_15/server1.go)): + * 增加一个检查错误的函数`checkError(error)`;讨论如下方案的利弊:为什么这个重构可能并没有那么理想?看看在[示例15.14](examples/chapter_15/template_validation.go)中它是如何被解决的 * 使客户端可以通过发送一条命令SH来关闭服务器 * 让服务器可以保存已经连接的客户端列表(他们的名字);当客户端发送WHO指令的时候,服务器将显示如下列表: @@ -199,6 +208,7 @@ User CHRIS is 1 下边这个版本的 simple_tcp_server.go 从很多方面优化了第一个tcp服务器的示例 server.go 并且拥有更好的结构,它只用了80行代码! 示例 15.5 [simple_tcp_server.go](examples/chapter_15/simple_tcp_server.go): + ```go // Simple multi-thread/multi-core TCP server. package main @@ -286,7 +296,9 @@ func checkError(error error, info string) { (**译者注:应该是由于go版本的更新,会提示os.EAGAIN undefined ,修改后的代码:[simple_tcp_server_v1.go](examples/chapter_15/simple_tcp_server_v1.go)**) 都有哪些改进? + * 服务器地址和端口不再是硬编码,而是通过命令行传入参数并通过`flag`包来读取这些参数。这里使用了`flag.NArg()`检查是否按照期望传入了2个参数: + ```go if flag.NArg() != 2{ panic("usage: host port") diff --git a/eBook/15.2.md b/eBook/15.2.md index eabd30c..aea6d9a 100644 --- a/eBook/15.2.md +++ b/eBook/15.2.md @@ -8,6 +8,7 @@ Http是一个比tcp更高级的协议,它描述了客户端浏览器如何与 `http.URL`描述了web服务器的地址,内含存放了url字符串的`Path`属性;`http.Request`描述了客户端请求,内含一个`URL`属性 如果`req`请求是一个POST类型的html表单,“var1”就是html表单中一个输入属性的名称,然后用户输入的值就可以通过GO代码:`req.FormValue("var1")`获取到(请看[章节15.4](15.4.md))。还有一种方法就是先执行`request.ParseForm()`然后再获取`request.Form["var1"]的第一个返回参数,就像这样: + ```go var1, found := request.Form["var1"] ``` @@ -24,6 +25,7 @@ Http是一个比tcp更高级的协议,它描述了客户端浏览器如何与 总结:第一个参数是请求的路径,第二个参数是处理这个路径请求的函数的引用。 示例 15.6 [hello_world_webserver.go](examples/chapter_15/hello_world_webserver.go): + ```go package main diff --git a/eBook/15.3.md b/eBook/15.3.md index 4cca937..35a2233 100644 --- a/eBook/15.3.md +++ b/eBook/15.3.md @@ -5,6 +5,7 @@ 返回状态码会被打印出来。 示例 15.7 [poll_url.go](examples/chapter_15/poll_url.go): + ```go package main @@ -32,12 +33,14 @@ func main() { } ``` 输出为: + ``` http://www.google.com/ : 302 Found http://golang.org/ : 200 OK http://blog.golang.org/ : 200 OK ``` ***译者注*** 由于国内的网络环境现状,很有可能见到如下超时错误提示: + ``` Error: http://www.google.com/ Head http://www.google.com/: dial tcp 216.58.221.100:80: connectex: A connection attempt failed because the connected pa rty did not properly respond after a period of time, or established connection failed because connected host has failed to respond. @@ -45,6 +48,7 @@ rty did not properly respond after a period of time, or established connection f 在下边的程序中我们使用`http.Get()`获取网页内容; `Get`的返回值`res`中的`Body`属性包含了网页内容,然后我们用`ioutil.ReadAll`把它读出来: 示例 15.8 [http_fetch.go](examples/chapter_15/http_fetch.go): + ```go package main @@ -79,6 +83,7 @@ func checkError(err error) { 在下边的程序中,我们获取一个twitter用户的状态,通过`xml`包将这个状态解析成为一个结构: 示例 15.9 [twitter_status.go](examples/chapter_15/twitter_status.go) + ```go package main @@ -110,12 +115,14 @@ func main() { } ``` 输出: + ``` status: Robot cars invade California, on orders from Google: Google has been testing self-driving cars ... http://bit.ly/cbtpUN http://retwt.me/97p ``` **译者注** 和上边的示例相似,你可能无法获取到xml数据,另外由于go版本的更新,`xml.Unmarshal`函数的第一个参数需是[]byte类型,而无法传入`Body`。 我们会在[章节15.4](15.4.md)中用到`http`包中的其他重要的函数: + * `http.Redirect(w ResponseWriter, r *Request, url string, code int)`:这个函数会让浏览器重定向到url(是请求的url的相对路径)以及状态码。 * `http.NotFound(w ResponseWriter, r *Request)`:这个函数将返回网页没有找到,HTTP 404错误。 * `http.Error(w ResponseWriter, error string, code int)`:这个函数返回特定的错误信息和HTTP代码。 diff --git a/eBook/15.4.md b/eBook/15.4.md index e246b8f..e092820 100644 --- a/eBook/15.4.md +++ b/eBook/15.4.md @@ -2,7 +2,8 @@ 下边的程序在端口8088上启动了一个网页服务器;`SimpleServer`会处理`/test1`url使它在浏览器输出`hello world`。`FormServer`会处理`/test2`url:如果url最初由浏览器请求,那么它就是一个`GET`请求,并且返回一个`form`常量,包含了简单的`input`表单,这个表单里有一个文本框和一个提交按钮。当在文本框输入一些东西并点击提交按钮的时候,会发起一个`POST`请求。`FormServer`中的代码用到了`switch`来区分两种情况。在`POST`情况下,使用`request.FormValue("inp")`通过文本框的`name`属性`inp`来获取内容,并写回浏览器页面。在控制台启动程序并在浏览器中打开url`http://localhost:8088/text2`来测试这个程序: -示例 15.10 [simple_webserver.go](examples/chapter_15/simple_webserver.go) +示例 15.10 [simple_webserver.go](examples/chapter_15/simple_webserver.go) + ```go package main @@ -59,3 +60,7 @@ func main() { 编写一个网页程序,可以让用户输入一连串的数字,然后将它们打印出来,计算出这些数字的均值和中值,就像下边这张截图一样: ![](../images/15.4_fig15.1.jpg?raw=true) + +- [目录](directory.md) +- 上一章:[访问并读取页面](15.4.md) +- 下一节:[常见的陷阱与错误](16.0.md) diff --git a/eBook/18.10.md b/eBook/18.10.md index 79c42d8..d1284c1 100644 --- a/eBook/18.10.md +++ b/eBook/18.10.md @@ -9,10 +9,11 @@ if err != nil { } ``` -或者: +或者: + ```go if err != nil { -panic(“ERROR occurred: “ + err.Error()) + panic(“ERROR occurred: “ + err.Error()) } ``` diff --git a/eBook/18.4.md b/eBook/18.4.md index 1d43d87..2ed1b29 100644 --- a/eBook/18.4.md +++ b/eBook/18.4.md @@ -1,6 +1,7 @@ # 18.4 结构体 -创建: +创建: + ```go type struct1 struct { field1 type1 @@ -10,7 +11,8 @@ type struct1 struct { ms := new(struct1) ``` -初始化: +初始化: + ```go ms := &struct1{10, 15.5, "Chris"} ```