# 12.10.2 服务端设置超时时间

在这小节，您将学习如何在服务端超时连接。您需要这样做，因为有时客户端结束 HTTP 连接的时间比预期的要长得多。这通常由于俩个原因而发生：第一个原因是客户端软件有 bug，第二个原因是服务进程正经历攻击！

在 `serverTimeOut.go` 源码文件中实现了这个技巧，并分四部分介绍。

`serverTimeOut.go` 的第一部分如下：

```go
package main

import (
    "fmt"
    "net/http"
    "os"
    "time"
)

func myHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
    fmt.Fprintf("Served: %s\n", r.Host)
}
```

`serverTimeOut.go` 的第二部分代码如下：

```go
func timeHandler(w http.ResponseWriter, r *http.Request) {
    t := time.Now().Format(time.RFC1123)
    Body := "The current time is:"
    fmt.Fprintf(w, "<h1 align=\"center\">%s</h1>", Body)
    fmt.Fprintf(w, "<h2 align=\"center\">%s</h2>n", t)
    fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
    fmt.Printf("Served time for :%s\n", r.Host)
}
```

`serverTimeOut.go` 的第三段代码如下：

```go
func main() {
    PORT := ":8001"
    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Printf("Listening on http://0.0.0.0%s\n", PORT)
    } else {
        PORT = ":" + arguments[1]
        fmt.Printf("Listening on http://0.0.0.0%s\n", PORT)
    }

    m := http.NewServeMux()
    srv := &http.Server {
        Addr: PORT,
        Handler: m,
        ReadTimeout: 3 * time.Second,
        WriteTimeout: 3 * time.Second,
    }
```

在这个例子中，我们使用 `http.Server` 结构, 它的字段支持两类超时。第一个叫 `ReadTimeout`，第二个叫 `WriteTimeout`。`ReadTimeout` 字段的值定义读取整个请求，包括消息体的最大持续时间。

`WriteTimeout` 字段的值定义超时写入响应之前的最大持续时间。简单说，这是从请求头读取结束到响应写入结束的时间。

`serverTimeOut.go` 的剩余代码如下：

```go
    m.HandleFunc("/time". timeHandler)
    m.HandleFunc("/", myHandler)

    err := srv.ListenAndServe()
    if err != nil {
        fmt.Println(err)
        return
    }
}
```

我们现在执行 `serverTimeOut.go`，使用 `nc(1)` 与之交互。

```
$ go run serverTimeOut.go
Listening on http://0.0.0.0:8001
```

在 `nc(1)` 部分（在这个例子中作为一个虚拟 HTTP 客户端），您应该发出下一个命令来连接到 `serverTimeOut.go` :

```
$ time nc localhost 8001

real 0m3.012s
user 0m0.001s
sys  0m0.002s
```

由于我们没有发出任何命令，HTTP 服务器结束了连接。`time(1)` 程序的输出验证了服务器关闭连接所用时间。
