mirror of
https://github.com/unknwon/the-way-to-go_ZH_CN.git
synced 2025-08-12 02:35:53 +08:00
@@ -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")
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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<exit code="0" msg="process exited normally"/>
|
||||
```
|
||||
**译者注** 和上边的示例相似,你可能无法获取到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代码。
|
||||
|
@@ -3,6 +3,7 @@
|
||||
下边的程序在端口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)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
@@ -59,3 +60,7 @@ func main() {
|
||||
编写一个网页程序,可以让用户输入一连串的数字,然后将它们打印出来,计算出这些数字的均值和中值,就像下边这张截图一样:
|
||||
|
||||

|
||||
|
||||
- [目录](directory.md)
|
||||
- 上一章:[访问并读取页面](15.4.md)
|
||||
- 下一节:[常见的陷阱与错误](16.0.md)
|
||||
|
@@ -10,9 +10,10 @@ if err != nil {
|
||||
```
|
||||
|
||||
或者:
|
||||
|
||||
```go
|
||||
if err != nil {
|
||||
panic(“ERROR occurred: “ + err.Error())
|
||||
panic(“ERROR occurred: “ + err.Error())
|
||||
}
|
||||
```
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
# 18.4 结构体
|
||||
|
||||
创建:
|
||||
|
||||
```go
|
||||
type struct1 struct {
|
||||
field1 type1
|
||||
@@ -11,6 +12,7 @@ ms := new(struct1)
|
||||
```
|
||||
|
||||
初始化:
|
||||
|
||||
```go
|
||||
ms := &struct1{10, 15.5, "Chris"}
|
||||
```
|
||||
|
Reference in New Issue
Block a user