前言

通过golang实现Tcp的连接与信息传输

本文主要介绍Tcp协议以及如何使用golang来建立一个简单的tcp连接服务,并且实现信息的传输。

首先介绍什么是Tcp协议

Tcp协议是传输层的一个可靠数据传输协议,Tcp协议有以下几个特点:

  • 点对点的发送:一个发送方,一个接收方
  • 可靠性: 可靠的、按序的字节流
  • 流水线机制:TCP拥塞控制和流量控制机制设置滑动窗口尺寸
  • 缓存窗口: 发送方/接收方可以进行缓存
  • 全双工:同一连接中能够传输双向数据流
  • 面向连接:通信双方在发送数据之前必须建立连接,在建立连接之后才能进行数据传输
    • 连接状态只在连接的两端中维护,在沿途节点中并不维护状态(端到端)
    • TCP连接包括:两台主机上的缓存、连接状态变量、socket等(双方都要维护)

什么是可靠数据传输?

TCP在IP层提供的不可靠服务基础上实现的可靠数据传输服务,基于流水线机制。当有发送端的数据丢失后,接收端不会不予理睬,而是重新会发送给发送方一个信号,请求重新发送该数据报。以此来确保数据的可靠性传输。这里只作简单解释可靠数据传输的特点:

  • 累计确认机制:当接收方接收到因为超时重传的帧后,会传输当前累加后的(最大的)ACK序号。
  • TCP使用单一重传定时器(也就是SR定时器,只判断ACK的那个帧进行定时处理)
  • 触发重传的事件:超时、收到重复ACK
  • 渐进式:暂不考虑重复ACK、暂不考虑流量控制、暂不考虑拥塞控制

TCP的快速重传机制

如果TCP通道建立之后,数据在发送过程中丢失。TCP将会触发快速重传机制,下面是快速重传机制的特点:

  • 如果发生超时情况,而超时时间间隔过长,则需要等待很长时间。
  • 当发送方接收到3个重复的ACK,就触发快速重传机制,直接重新发送这个帧数据。

简单介绍TCP连接的三次握手和四次挥手

三次握手

SYNSYNACKSYNACKACK

四次挥手

FIN_WAIT_1close_waitCLOSE_WAITFIN_WAIT_2LAST_ACKTIME-WAITCLOSEDCLOSED

golang实现简单的tcp连接建立

服务端

主要分为3部分

  • 建立tcp监听通道,指定监听端口
net.Listen("tcp", "127.0.0.1:4399")  (Listener, error)
  • 对通道进行监听
listen.Accept() (Conn, error)
  • 关闭监听通道
defer listen.Close()

完整代码

deferdefer
package main
import (
   "fmt"
   "net"
)
func handle(conn net.Conn) {
   defer conn.Close()
   var info [256]byte
   n, err := conn.Read(info[:])
   if err != nil {
      fmt.Println("conn Read fail ,err = ", err)
      return
   }
   fmt.Println("client send info to server si : ", string(info[:n]))
}
func main() {
   // 1. 建立tcp连接监听通道
   listen, err := net.Listen("tcp", "127.0.0.1:4399")
   if err != nil {
      panic(err)
   }
   // 3. 关闭监听通道
   defer listen.Close()
   fmt.Println("server is Listening")
   for {
      // 2. 进行通道监听
      conn, err := listen.Accept()
      if err != nil {
         panic(err)
      }
      // 启动一个协程去单独处理该连接
      go handle(conn)
   }
}

客户端

客户端和服务端一样,也分为三个部分

  • 对指定通道进行连接
net.Dial("tcp", "127.0.0.1:4399") (Conn, error)
  • 连接成功后发送数据
msg := "Hi, I am a client"
conn.Write([]byte(msg))
  • 发送完成后进行关闭连接
defer conn.Close()

完整代码

Writefor
package main
import "net"
func main() {
   // 1. 建立访问通道
   conn, err := net.Dial("tcp", "127.0.0.1:4399")
   if err != nil {
      panic(err)
   }
   defer conn.Close()
   msg := "Hi, I am a client"
   conn.Write([]byte(msg))
}