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数据传输的资料请关注脚本之家其它相关文章!

相关文章

  • RoaringBitmap原理及在Go中的使用详解

    RoaringBitmap原理及在Go中的使用详解

    这篇文章主要为大家介绍了RoaringBitmap原理及在Go中的使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • golang rate令牌桶源码分析实现方式

    golang rate令牌桶源码分析实现方式

    这篇文章主要介绍了golang rate令牌桶源码分析实现方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Go gRPC服务proto数据验证进阶教程

    Go gRPC服务proto数据验证进阶教程

    这篇文章主要为大家介绍了Go gRPC服务proto数据验证进阶教程示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • Go错误处理之panic函数和recover函数使用及捕获异常方法

    Go错误处理之panic函数和recover函数使用及捕获异常方法

    这篇文章主要介绍了Go错误处理之panic函数使用及捕获,本篇探讨了如何使用 panic 和 recover 来处理 Go 语言中的异常,需要的朋友可以参考下
    2023-03-03
  • 一键定位Golang线上服务内存泄露的秘籍

    一键定位Golang线上服务内存泄露的秘籍

    内存泄露?别让它拖垮你的Golang线上服务!快速掌握Go语言服务内存泄漏排查秘籍,从此问题无处遁形,一文读懂如何精准定位与有效解决Golang应用中的内存问题,立即阅读,让性能飞升!
    2024-01-01
  • Golang PHP 数据绑定示例分析

    Golang PHP 数据绑定示例分析

    这篇文章主要为大家介绍了Golang PHP 数据绑定示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • 一文带大家了解Go语言中的内联优化

    一文带大家了解Go语言中的内联优化

    内联优化是一种常见的编译器优化策略,通俗来讲,就是把函数在它被调用的地方展开,这样可以减少函数调用所带来的开销,本文主要为大家介绍了Go中内联优化的具体使用,需要的可以参考下
    2023-05-05
  • Go高级特性探究之HTTP错误处理详解

    Go高级特性探究之HTTP错误处理详解

    在Web应用程序中,HTTP错误处理是非常重要的,它关系到Web应用程序的稳定性和可靠性,本文介绍如何在Go项目中处理HTTP错误,并提供相应的解决方案和实践经验,希望对Go语言Web应用程序的开发者有所帮助
    2023-06-06
  • Go初学者踩坑之go mod init与自定义包的使用

    Go初学者踩坑之go mod init与自定义包的使用

    go mod是go的一个模块管理工具,用来代替传统的GOPATH方案,下面这篇文章主要给大家介绍了关于Go初学者踩坑之go mod init与自定义包的使用,需要的朋友可以参考下
    2022-10-10
  • Go设计模式之原型模式图文详解

    Go设计模式之原型模式图文详解

    原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类,本文将通过图片和文字让大家可以详细的了解Go的原型模式,感兴趣的通过跟着小编一起来看看吧
    2023-07-07

最新评论