quic-go源码一---server启动

打印 上一主题 下一主题

主题 925|帖子 925|积分 2775

前言:

走马观花地看了RFC 9000UIC: A UDP-Based Multiplexed and Secure Transport,
感受不是那么直观,以是再来看看这个协议的golang语言实现:quic-go,增强学习。
https://quic-go.net/docs/quic/quic-go文档

本篇准备的代码片断如下:
  1. const addr = "127.0.0.1:9000"
  2. func main() {
  3.         quicConf := &quic.Config{
  4.                 InitialStreamReceiveWindow:     1 << 20,  // 1 MB
  5.                 MaxStreamReceiveWindow:         6 << 20,  // 6 MB
  6.                 InitialConnectionReceiveWindow: 2 << 20,  // 2 MB
  7.                 MaxConnectionReceiveWindow:     12 << 20, // 12 MB
  8.         }
  9.         // 学习点1
  10.         listener, err := quic.ListenAddr(addr, generateTLSConfig(), quicConf)
  11.         if err != nil {
  12.                 log.Fatalf("Error listening on address: %v", err)
  13.         }
  14.         defer listener.Close()
  15.         for {
  16.                 // 学习点2
  17.                 conn, err := listener.Accept(context.Background())
  18.                 if err != nil {
  19.                         log.Printf("Error accepting connection: %v", err)
  20.                         continue
  21.                 }
  22.                 go handleConnection(conn)
  23.                 fmt.Println("New client connected")
  24.         }
  25. }
  26. func handleConnection(conn quic.Connection) {
  27.         for {
  28.                 // 接收数据流
  29.                 stream, err := conn.AcceptStream(context.Background())
  30.                 // 。。。。。。
  31.         }
  32. }
  33. func generateTLSConfig() *tls.Config {
  34.         key, err := rsa.GenerateKey(rand.Reader, 1024)
  35.         if err != nil {
  36.                 panic(err)
  37.         }
  38.         template := x509.Certificate{SerialNumber: big.NewInt(1)}
  39.         certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, &key.PublicKey, key)
  40.         if err != nil {
  41.                 panic(err)
  42.         }
  43.         keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)})
  44.         certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certDER})
  45.         tlsCert, err := tls.X509KeyPair(certPEM, keyPEM)
  46.         if err != nil {
  47.                 panic(err)
  48.         }
  49.         return &tls.Config{
  50.                 Certificates: []tls.Certificate{tlsCert},
  51.                 NextProtos:   []string{"TEST"},
  52.         }
  53. }
复制代码
看点1

  1. listener, err := quic.ListenAddr(addr, generateTLSConfig(), quicConf)
复制代码
先记住参数
  1. createdConn: true,
  2. isSingleUse: true,
复制代码

其中conn, err := listenUDP(addr)是net udp常规操纵,略过不提。
以是核心是调用了Transport.Listener(tlsConf, quicConf)方法。但是注意其中的参数,呃,我们先看官网文档:

使用简写方式:我们demo正是如此:

看看官方的实现:恰好印证了文档的正确性:

接着看 Transport.Listen(…)



上述allow0RTT为true/false的区别在于,以是当使用ListenEarly(。。。)(allow0RTT为true)时,服务端会开辟一个map:

官网文档如下:To allow clients to use 0-RTT resumption, the Allow0RTT flag needs to be set on the quic.Config.(为了能够使用0-RTT, 需要在 quic.Config设置Allow0RTT标识)
固然也得用ListenEarly() 而不是Listen()

allow0RTT在本篇只是带过,知道有个概念,后续有机会学习分析。。。
接着看 Transport.createServer(…)


validateConfig(…):


populateConfig(config *Config)


t.init(false)


wrapConn(..)核心如下:
  1. setReceiveBuffer(pc net.PacketConn)
  2. setSendBuffer(pc)
  3. supportsDF, err = setDF(rawConn)
  4. // 优化点在这里!
  5. c, ok := pc.(OOBCapablePacketConn)
  6. if !ok {
  7.         return &basicConn{PacketConn: pc, supportsDF: supportsDF}, nil
  8. }
  9. return newConn(c, supportsDF)
复制代码
其中前2项性质都一样:
  1. _ = conn.SetReadBuffer(protocol.DesiredReceiveBufferSize) // 7 MB
  2. err := fd.pfd.SetsockoptInt(syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
  3. size, serr = unix.GetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_SNDBUF)
复制代码

其中setDF(rawConn syscall.RawConn)实现紧张逻辑如下:
  1. errDFIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_DONTFRAG, 1)
  2. errDFIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_DONTFRAG, 1)
复制代码

再看看newConn(...)

只激活了读取ipv4的ECN:


末了返回的conn如下:

说完了wrapConn(...)后再回到init(...)


  1. // is closed when listen returns
  2. t.listening = make(chan struct{})
复制代码

DefaultConnectionIDGenerator初始化:

getMultiplexer().AddConn(t.Conn):
  1. func getMultiplexer() multiplexer {
  2.         connMuxerOnce.Do(func() {
  3.                 connMuxer = &connMultiplexer{
  4.                         conns:  make(map[string]indexableConn),
  5.                         logger: utils.DefaultLogger.WithPrefix("muxer"),
  6.                 }
  7.         })
  8.         return connMuxer
  9. }
  10. func (m *connMultiplexer) AddConn(c indexableConn) {
  11.         m.mutex.Lock()
  12.         defer m.mutex.Unlock()
  13.         connIndex := m.index(c.LocalAddr())
  14.         p, ok := m.conns[connIndex]
  15.         if ok {
  16.                 // 后续会去掉panic(...)
  17.                 panic("connection already exists") // TODO: write a nice message
  18.         }
  19.         m.conns[connIndex] = p
  20. }
复制代码
尚有末了2行代码:协程启动的:

  1. go t.listen(conn)
  2. go t.runSendQueue()
复制代码

这里先不展开怎样处理数据包的逻辑,先把整体流程熟悉起来。

init方法终于结束了!还差末了一个newServer(...):



  1. go s.run()
  2. go s.runSendQueue()
复制代码

正是transport.handlePacket(p receivedPacket)调用server.handlePacket(p receivedPacket)
  1. func (s *baseServer) handlePacket(p receivedPacket) {
  2.         select {
  3.         case s.receivedPackets <- p: // 【看这里看这里看这里看这里】
  4.         default:
  5.                 s.logger.Debugf("Dropping packet from %s (%d bytes). Server receive queue full.", p.remoteAddr, p.Size())
  6.                 if s.tracer != nil && s.tracer.DroppedPacket != nil {
  7.                         s.tracer.DroppedPacket(p.remoteAddr, logging.PacketTypeNotDetermined, p.Size(), logging.PacketDropDOSPrevention)
  8.                 }
  9.         }
  10. }
复制代码
但是上面第299行的s.handlePacketImpl(p)很紧张,后续篇再分析。

  1. func (s *baseServer) sendRetry(p rejectedPacket) {
  2.         if err := s.sendRetryPacket(p); err != nil {
  3.                 s.logger.Debugf("Error sending Retry packet: %s", err)
  4.         }
  5. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莫张周刘王

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表