> 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.2.md).

# 13.2 TCP 客户端

由于从之前的章节，您已经知道了，TCP 代表**传输控制协议**，并且它的主要特点是可靠性。每个包的 TCP 头部包含**源端口**和**目标端口**字段。这俩个字段，加上源和目标 IP 地址，组合成唯一标识单个 TCP 连接。这节实现的 TCP 客户端命名为 TCPclient.go，它由以下四部分构成。第一部分代码：

```go
package main

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

第二部分代码：

```go
func main(){
    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Println("Please provide host:port.")
        return
    }
    CONNECT := arguments[1]
    c, err := net.Dial("tcp", CONNECT)
    if err != nil {
        fmt.Println(err)
        return
    }
```

net.Dial() 方法连接远端服务器。这个方法的第一个参数定义使用的网络连接类型，第二个参数定义服务器地址，并且必须包含端口号。第一个参数的有效值为 tcp，tcp4 **(IPv4-only)**，tcp6 **(IPv6-ony)**，udp， udp4 **(IPv4-only)**，udp6 **(IPv6-only)**，ip，ip4 **(IPv4-only)**，ip6 **(IPv6-only)**，Unix **(Unix sockets)**，Unixgram 和 Unixpacket。

第三部分代码：

```go
for {
    reader := bufio.NewReader(os.Stdin)
    fmt.Print(">> ")
    text, _ := reader.ReadString('\n')
    fmt.Fprintf(c, text + "\n")
```

前面这段代码用于从用户获取输入，使用 `os.Stdin` 文件进行验证读取。忽略从 `reader.ReadString()` 返回的 `error` 值不是一个好的实现，但它节省了空间。当然，你永远不要在正式软件中这样做。

最后一段代码：

```go
        message, _ := bufio.NewReader(c).ReadString('\n')
        fmt.Print("->: " + message)
        if strings.TrimSpace(string(text)) == "STOP" {
            fmt.Println("TCP client exiting...")
            return
        }
    }
}
```

为了测试，`TCPclient.go` 将连接由 `netcat(1)` 实现的TCP 服务器，它将产生以下输出：

```
$ go run TCPclient.go 8001
dial tcp: address 8001: missing port in address
$ go run TCPclient.go localhost:8001
>> Hello from TCPclient.go!
->: Hi from nc!

>> STOP
->:
TCP client exiting...
```

*请注意，给定协议如 TCP 和 UDP 的客户端本质上是可以通用的，这意味着它能够与支持其协议的多种服务器通信。您很快会看到，并不是使用指定协议的服务端应用必须实现指定的功能*
