> For the complete documentation index, see [llms.txt](https://wskdsgcf.gitbook.io/mastering-go-zh-cn/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wskdsgcf.gitbook.io/mastering-go-zh-cn/13.0/13.3.md).

# 13.3 TCP 服务器

这节编写一个 TCP 服务器，给客户端返回一个当前日期和时间的网络包。在实践中，这意味着服务器在接收到一个客户端连接后，将从 Unix 系统获取时间和日期，并把这个数据返回给客户端。

这个工具命名为 TCPserver.go，并由 4 部分构成。

第一部分：

```go
package main

import(
    "bufio"
    "fmt"
    "net"
    "os"
    "strings"
    "time"
)
```

第二部分包含以下代码：

```go
func main() {
    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Println("Please provide port number")
        return
    }

    PORT := ":" + arguments[1]
    l, err := net.Listen("tcp" , PORT)
    if err != nil {
        fmt.Println(err)
        return
    }
    defer l.Close()
```

net.Listen() 函数用于监听连接。如果第二个参数不包含 IP 地址，只有端口号的话，net.Listen() 将监听本地系统上所有可用的 IP 地址。

TCPserver.go 的第三段如下：

```go
    c, err := l.Accept()
    if err != nil {
        fmt.Println(err)
        return
    }
```

Accept() 函数等待接收连接并返回一个通用的 `Conn` 变量。这个特定的 TCP 服务器有个错误是它只能接收第一个与它建立连接的 TCP 客户端，因为 Accept() 函数是在接下来的 `for` 循环外调用的。

TCPserver.go 的剩余代码如下：

```go
    for {
        netData, err := bufio.NewReader(c).ReadString('\n')
        if err != nil {
            fmt.Println(err)
            return
        }
        if strings.TrimSpace(string(netData)) == "STOP" {
            fmt.Println("Exiting TCP server!")
            return
        }
        fmt.Print("-> ", string(netData))
        t := time.Now()
        myTime := t.Format(time.RFC3339) + "\n"
        c.Write([]byte(myTime))
    }
}
```

执行 TCPServer.go 并使用一个 TCP 客户端应用和它交互，将产生如下输出：

```
$ go run TCPServer.go 8001
-> HELLO
Exiting TCP server!
```

在客户端这边，您将看到如下输出：

```
$ nc 127.0.0.1 8001
HELLO
2018-05-07T14:40:05+03:00
STOP
```

如果这个 TCPServer.go 工具试图使用一个被其他 Unix 进程占用的 TCP 端口，您将看到下面的错误信息：

```
$ go run TCPserver.go 9000
listen tcp :9000: bind: address already in use
```

最后，如果这个 TCPServer.go 工具试图使用一个在 1-1024 范围内需要 root 权限的 TCP 端口，您将看到下面的错误信息：

```
$ go run TCPserver.go 80
listen tcp :80: bind: permission denied
```
