TCP 服务器

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

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

第一部分:

  1. package main
  2. import(
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "os"
  7. "strings"
  8. "time"
  9. )

第二部分包含以下代码:

  1. func main() {
  2. arguments := os.Args
  3. if len(arguments) == 1 {
  4. fmt.Println("Please provide port number")
  5. return
  6. }
  7. PORT := ":" + arguments[1]
  8. l, err := net.Listen("tcp" , PORT)
  9. if err != nil {
  10. fmt.Println(err)
  11. return
  12. }
  13. defer l.Close()

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

TCPserver.go 的第三段如下:

  1. c, err := l.Accept()
  2. if err != nil {
  3. fmt.Println(err)
  4. return
  5. }

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

TCPserver.go 的剩余代码如下:

  1. for {
  2. netData, err := bufio.NewReader(c).ReadString('\n')
  3. if err != nil {
  4. fmt.Println(err)
  5. return
  6. }
  7. if strings.TrimSpace(string(netData)) == "STOP" {
  8. fmt.Println("Exiting TCP server!")
  9. return
  10. }
  11. fmt.Print("-> ", string(netData))
  12. t := time.Now()
  13. myTime := t.Format(time.RFC3339) + "\n"
  14. c.Write([]byte(myTime))
  15. }
  16. }

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

  1. $ go run TCPServer.go 8001
  2. -> HELLO
  3. Exiting TCP server!

在客户端这边,您将看到如下输出:

  1. $ nc 127.0.0.1 8001
  2. HELLO
  3. 2018-05-07T14:40:05+03:00
  4. STOP

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

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

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

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