golang实现简单的tcp数据传输

 更新时间:2022年12月12日 10:22:42   作者:捶捶自己  
这篇文章主要为大家介绍了golang实现简单的tcp数据传输,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

前言

通过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连接的三次握手和四次挥手

三次握手

  • 客户端希望与服务端建立TCP连接时,需要先发送一个SYN请求报文段给服务端,并告诉服务端自己的初始报文段序列号是多少。
  • 服务端接收到这个报文后进行随机选择初始的报文段序列号,分配滑动窗口缓存空间大小。接着返回一个SYNACK响应报文段并且把服务端初始报文段序列号和滑动窗口缓存空间大小给客户端表明我已经接到你的请求了。
  • 客户端接收到SYNACK报文段后会答复一个ACK报文段表明我已经收到,可以建立连接了。同时会根据接收到的服务端的滑动窗口缓存空间大小,分配一个同样大小的滑动窗口缓存空间用于发送。

四次挥手

  • 客户端进程发出连接释放的报文FIN=1以及一个客户端的序列号(该序列号等于最后一个传进来的数据的序列号+1)给服务端,并进入FIN_WAIT_1的终止等待状态。TCP规定FIN报文段即使不携带数据,也要消耗一个序号。
  • 服务端收到客户端发来的请求报文和序列号后,响应给客户端ACK=1确认报文段,服务端的报文序列号,以及ack=u+1。此时服务端进入close_wait状态(关闭等待状态)。此时TCP通知上层应用进程,客户端已经准备关闭了,这时候处于版关闭状态。这时如果向客户端发送数据,客户端仍然需要接收。这个状态需要维持一段时间,如果期间有数据需要发送就进行发送。等待整个CLOSE_WAIT状态持续时间结束。
  • 客户端收到服务端发来的ACK=1确认报文后,进入FIN_WAIT_2的终止等待状态,等待服务端是否还有数据需要进行发送。
  • 服务端发送完最后的数据之后,就向客户端发送连接释放报文,FIN=1,ack=u+1。由于在半关闭状态,服务器可能还会发送一些数据,所以这时的序列号也会随之改变。服务端发送完的报文序列号之后就进入LAST_ACK最后确认状态,等待客户端进行确认。
  • 客户端收到服务端发送的连接释放报文后必须发送确认ACK=1报文,以及自己的序列号给服务端表示已经接收并进入TIME-WAIT(时间等待状态)注意此时客户端并未关闭,而是经过2*MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB之后才进入CLOSED状态。
  • 服务端只要接收到客户端的确认连接释放报文,就立即进入CLOSED关闭状态,同样撤销掉了TCB之后就结束了这次的TCP连接。因此可以看出,(除非特殊情况)服务端关闭是要早于客户端的。

golang实现简单的tcp连接建立

服务端

主要分为3部分

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

完整代码

注意defer语句一定要写在错误处理之后。如果写在错误之前,一旦发生了错误,该连接就不会被生成,进而执行defer语句的时候无法进行通道关闭。

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()

完整代码

在这里我只做了简单的处理,将字符串转化为字符切片通过Write的方式发送给了服务端,并且该过程只进行了一次。如果需要多次持续建立连接并且发送,需要主动开启一个for循环,并且设置循环结束条件。

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))
}

以上就是golang实现简单的tcp数据传输的详细内容,更多关于golang tcp数据传输的资料请关注脚本之家其它相关文章!

相关文章

  • golang 中signal包的Notify用法说明

    golang 中signal包的Notify用法说明

    这篇文章主要介绍了golang 中signal包的Notify用法说明,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • Golang中时间格式化的实现详解

    Golang中时间格式化的实现详解

    这篇文章主要为大家详细介绍了Go语言中进行时间进行格式化的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起了解一下
    2023-09-09
  • Golang中String,rune和byte的相互转换

    Golang中String,rune和byte的相互转换

    Go语言中,string就是只读的采用utf8编码的字节切片,rune是int32的别名,代表字符的Unicode编码,这篇文章主要介绍了Golang中String,rune和byte的相互转换,感兴趣的小伙伴可以了解一下
    2023-10-10
  • golang的Pseudo-versions使用问题解析

    golang的Pseudo-versions使用问题解析

    这篇文章主要为大家介绍有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪了golang的Pseudo-versions使用问题解析,
    2023-07-07
  • 详解如何在Go中实现优雅停止

    详解如何在Go中实现优雅停止

    和其他语言相比,Go 中有相同也有不同,相同的是实现思路上和其他语言没啥差异,不同在于 Go 采用的是 goroutine + channel 的并发模型,与传统的进程线程相比,实现细节上存在差异,本文将从实际场景和它的一般实现方式展开,逐步讨论这个话题,需要的朋友可以参考下
    2024-04-04
  • go语言变量定义用法实例

    go语言变量定义用法实例

    这篇文章主要介绍了go语言变量定义用法,实例分析了go语言变量的定义及使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-02-02
  • Golang连接并操作PostgreSQL数据库基本操作

    Golang连接并操作PostgreSQL数据库基本操作

    PostgreSQL是常见的免费的大型关系型数据库,具有丰富的数据类型,也是软件项目常用的数据库之一,下面这篇文章主要给大家介绍了关于Golang连接并操作PostgreSQL数据库基本操作的相关资料,需要的朋友可以参考下
    2022-09-09
  • golang import自定义包方式

    golang import自定义包方式

    这篇文章主要介绍了golang import自定义包方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • golang特有程序结构入门教程

    golang特有程序结构入门教程

    GO语言是一门不错的编程语言能够到达静态编译语言的安全和性能,在本文中重点给大家介绍goland特有程序结构及引用类型别名的特征,感兴趣的朋友跟随小编一起看看吧
    2021-06-06
  • Go语言中CGO的使用实践

    Go语言中CGO的使用实践

    本文主要介绍了Go语言中CGO的使用实践,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09

最新评论