Go中的TCP

533 阅读3分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

TCP

传输控制协议, 属于ISO七层网络模型中的传输层. 它是面向连接, 提供可靠的传输服务

TCP特点

  1. 面向连接
  2. 保证可靠交付
  3. 只支持一对一通信
  4. 提供全双工通信
  5. 传输字节流数据

TCP的三次握手

  1. 客户端首先发送一个请给服务器, 表示想要建立连接的请求
  2. 服务器端收到建立连接请求后, 回传给客户端确认信息
  3. 客户端再回传给服务器确认收到服务器发送的确认信息

TCP的四次挥手

  1. 客户端发送一个释放连接的请求给服务器
  2. 服务器收到释放连接的请求后, 回传给客户端表示确认收到
  3. 服务器发送一个释放连接的请求给客户端
  4. 客户端收到释放连接的请求后, 回传给服务器表示确认收到

TCP服务端流程

  1. 通过net.Listen()进行网络监听, 获得一个Listener实例

     type Listener interface {
        // 处理连接请求
        Accept() (Conn, error)
     ​
        // 关闭当前监听
        Close() error
        
       // 返回当前网络地址: ip + 端口号
        Addr() Addr
     }
    
  2. 通过listener.Accept()处理来自client的连接请求

  3. 通过一个goroutine来处理该连接请求

  4. 所有连接处理完毕之后, 关闭监听listener.Close()

TCP服务端代码

 import (
    "bufio"
    "fmt"
    "net"
 )
 ​
 func main() {
    // 监听端口
    listener, err := net.Listen("tcp", "127.0.0.1:1000")
    if err != nil {
       fmt.Println("listen failed: ", err)
       return
    }
    fmt.Println("tcp: 127.0.0.1:1000 监听成功")
 ​
    // 当程序退出的时候, 关闭监听
    defer func() {
       fmt.Println("listener closed")
       listener.Close()
    }()
 ​
    for {
 ​
       // 接收来自client的连接请求
       c, err := listener.Accept()
 ​
       // 请求错误
       if err != nil {
          fmt.Println("accept failed: ", err)
          continue
       }
 ​
       // 处理连接
       go dealConn(c)
    }
 }
 ​
 func dealConn(c net.Conn)  {
    // 当连接处理完之后, 关闭连接
    defer func() {
       fmt.Println("conn closed")
       c.Close()
    }()
 ​
    // 用于读取内容
    reader := bufio.NewReader(c)
 ​
    for {
       data := make([]byte, 16)
       n, err := reader.Read(data[:])
       if err != nil {
          fmt.Println("read failed: ", err)
          break
       }
       fmt.Println("read success: ", string(data[:n]))
 ​
       // 向client端返回数据
       c.Write(data[:n])
    }
 }

TCP客户端流程

  1. 调用net.Dial函数建立连接, 返回一个Conn实例

     type Conn interface {
        // 从连接中读取数据
        Read(b []byte) (n int, err error)
     ​
        // 向连接中写入数据
        Write(b []byte) (n int, err error)
     ​
        // 关闭当前连接
        Close() error
     ​
        // 本机地址
        LocalAddr() Addr
     ​
        // 远程主机地址
        RemoteAddr() Addr
     ​
       // 超时时间
        SetDeadline(t time.Time) error
     ​
        SetReadDeadline(t time.Time) error
     ​
        SetWriteDeadline(t time.Time) error
     }
    
  1. 调用Write函数向该连接写入数据
  2. 调用Read函数接收来自server端的响应
  3. 调用Close函数关闭该连接

TCP客户端代码

 import (
    "bufio"
    "fmt"
    "net"
    "os"
    "strings"
 )
 ​
 func main() {
    // 建立连接 ip地址为: 127.0.0.1, 端口号为: 1000
    c, err := net.Dial("tcp", "127.0.0.1:1000")
 ​
    // 建立连接失败
    if err != nil {
       fmt.Println("dial failed: ", err)
       return
    }
 ​
    // 在程序执行完之后, 关闭连接
    defer func() {
       fmt.Println("client conn closed!")
       c.Close()
    }()
 ​
 ​
 }
 ​
 func requestTCP(c net.TCPConn) {
    // 如果建立连接成功, 则向server端发送数据
    // 准备好要发送的数据 Write方法接收一个byte类型的切片
    reader := bufio.NewReader(os.Stdin)
 ​
    for {
       inData, _ := reader.ReadString('\n')
       data := strings.Trim(inData, "\n")
 ​
       // 如果输入的为Q, 则退出程序
       if strings.ToUpper(data) == "Q" {
          break
       }
 ​
       // 向server端发送数据
       _, err := c.Write([]byte(data))
 ​
       // 数据发送失败, 输出错误信息
       if err != nil {
          fmt.Println("write failed: ", err)
       }
 ​
       // 数据发送成功
       fmt.Println("write success")
 ​
       // 从server端接收数据
       serverData := make([]byte, 16)
       n, err := c.Read(serverData)
       if err != nil {
          fmt.Println("client recv failed: ", err)
          break
       }
       fmt.Println("client recv success: ", string(data[:n]))
    }
 }