一. QUIC 的基本特点 基于UDP的多路传输(单连接下); 极低的等待时延(相比于TCP的三次握手); 快速迭代更新; 开源于Chromium项目中。 首先,QUIC为 传输层 协议,与TCP、UDP、SCTP同级。所以肯定会 在一定范围内 同现有的传输层协议构成竞争关系。 二. 为什么不用TCP TCP由于基于操作系统内核实现,发展速度极慢,现有的TCP Fast Open实现等等虽然早已存在于标准中但是实际应用情况及其落后,即便除非所有机器的操作系统都更新到最新,否则考虑到兼容性不太可能大范围采用新技术。 QUIC直接基于客户端实现,而非基于系统内核(这点有点像最新的.Net Core),可以进行快速迭代更新,不需要操作系统内核层面的更改。 (TCP的性能缺陷将在下文中说明)。 像SCTP这样的传输层协议也都存在了10多年了但由于支持的操作系统内核太少也完全没有办法普及应用,所以基于UDP是一个更有效的选择。(并非是上层协议) 三. QUIC的发展路线 QUIC成为一个独立的传输层方案,成为更多应用层的高性能选择; QUIC的理念被TCP和TLS所采纳,使得TCP的性能得到充分发展,融合统一; 综上所述,Google并不是想取代TCP,但是确实想改TCP又改不了(内核实现的劣势),所以独立实现了QUIC协议作为替补方案。 四. 核心优势 多路复用 类似于SCTP的 多流 设计,可以通过一个连接同时进行多个请求,不必等待上一个请求返回浪费时间,也不必同时建立若干个连接浪费资源。 另外单流情况下若发生丢包则会有等待重传阻塞,影响整个连接的传输速度。 等待时延(Latency) Web访问的 用户体验 极大地取决于打开网站的等待时间,而TCP需要进行 三次握手 才能建立连接,具有一定的连接等待时延,如果用了TLS加密,还会有其他的步骤进一步增加时延。 QUIC采用了类似于TCP Fast Open的设计,在之前已经连接过的情况下可以无需握手,直接开始传送数据,连接建立时延为0。 为什么不直接用TCP Fast Open呢?因为TCP在内核呀,除非所有的服务器和客户端的操作系统都能支持并且都更新到能支持的版本才行。所以可能这辈子都不行,就像HTTP1也支持单连接承载多请求但还没有哪个浏览器支持的。 加密技术 总之看起来比TLS性能好很多,也具有各种攻击防御策略,这方面不是很懂。可以直接看视频或者相关文档。 前向纠错 QUIC和TCP一个主要的核心区别就是:TCP采用 重传 机制,而QUIC采用 纠错 机制。 如果发生丢包的话,TCP首先需要一个等待延时来判断发生了丢包,然后再启动重传机制,在此期间会对连接造成一定的阻塞(并且TCP窗口是缓慢增大的,Web这种突发性快速连接情况下窗口会相对较小),从而影响传输时间。 而QUIC采用了一种脑洞极大的前向纠错(FEC)方案,类似于RAID5,将N个包的校验和(异或)建立一个单独的数据包发送,这样如果在这N个包中丢了一个包可以直接恢复出来,完全不需要重传,有利于保证高速性,N可以根据网络状况动态调整。 速率控制而非拥塞控制 连接保持 在IP地址和端口变化的情况下(比如从Wi-Fi切换到流量),可以无需重新建立连接,继续通信。对移动设备的用户体验较为友好。 综上所述,QUIC确实是一个完善的传输层解决方案,在 Web 访问 上相对TCP确实具有一些优势。但是总的来说,不说取代,如果能达到和TCP相提并论的地步就已经非常不错了。 下面是golang基于quic协议实现的server代码 package main import ( "github.com/lucas-clemente/quic-go" "io" "fmt" "crypto/tls" "crypto/rsa" "crypto/x509" "math/big" "encoding/pem" "crypto/rand" ) const saddr = "localhost:9999" func main() { listener, err := quic.ListenAddr(saddr, generateTLSConfig(), nil) if err != nil { fmt.Println(err) } for{ sess, err := listener.Accept() if err != nil { fmt.Println(err) }else{ go dealSession(sess) } } } func dealSession(sess quic.Session){ stream, err := sess.AcceptStream() if err != nil { panic(err) }else{ for{ _, err = io.Copy(loggingWriter{stream}, stream) } } } type loggingWriter struct{ io.Writer } func (w loggingWriter) Write(b []byte) (int, error) { fmt.Printf("Server: Got '%s'\n", string(b)) return w.Writer.Write(b) } // Setup a bare-bones TLS config for the server func generateTLSConfig() *tls.Config { key, err := rsa.GenerateKey(rand.Reader, 1024) if err != nil { panic(err) } template := x509.Certificate{SerialNumber: big.NewInt(1)} certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key) if err != nil { panic(err) } keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}) certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER}) tlsCert, err := tls.X509KeyPair(certPEM, keyPEM) if err != nil { panic(err) } return &tls.Config{Certificates: []tls.Certificate{tlsCert}} } 下面是golang基于quic协议实现的client代码 package main import ( "github.com/lucas-clemente/quic-go" "io" "crypto/tls" "fmt" "time" ) const addr = "localhost:9999" const message = "ccc" func main() { session, err := quic.DialAddr(addr, &tls.Config{InsecureSkipVerify: true}, nil) if err != nil { fmt.Println(err) return } stream, err := session.OpenStreamSync() if err != nil { fmt.Println(err) return } for{ fmt.Printf("Client: Sending '%s'\n", message) _, err = stream.Write([]byte(message)) if err != nil { fmt.Println(err) return } buf := make([]byte, len(message)) _, err = io.ReadFull(stream, buf) if err != nil { fmt.Println(err) return } fmt.Printf("Client: Got '%s'\n", buf) time.Sleep(2*time.Second) } } 原文:https://blog.csdn.net/qq513036862/article/details/77914776
以上所述就是小编给大家介绍的《基于UDP协议可靠传输协议QUIC协议和golang server代码和client代码》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 关于TCP协议和UDP协议
- 接地气讲解 UDP 协议和网络程序设计
- Weblogic 12版本以下服务器如何调整SSL协议和加密套件
- 低代码、无代码、零代码
- 代码分析驱动代码质量
- 代码结构及一些代码规范建议
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。