5

BTCD源码阅读笔记-connmgr

 2 years ago
source link: https://imnisen.github.io/btcd-code-connmgr.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

1 connmgr模块

connmgr用来处理节点的连接,定义了一个 ConnManager ,用来管理request connect的连接、断开、失败、重试、限制最大连接数、重试次数等情况。

1.1 主要结构

// ConnManager provides a manager to handle network connections.
type ConnManager struct {
        // The following variables must only be used atomically.
        connReqCount uint64  // 管理的连接数
        start        int32  // 启动标识
        stop         int32 // 停止标志

        cfg            Config  // 配置
        wg             sync.WaitGroup  // 并发连接管理
        failedAttempts uint64  // 记录失败次数,如果成功连接则归0
        requests       chan interface{}  // 用于消息传递
        quit           chan struct{} // 用于退出
}


// ConnReq is the connection request to a network address. If permanent, the
// connection will be retried on disconnection.
type ConnReq struct {
        // The following variables must only be used atomically.
        id uint64  // 连接id,采用connReqCoount +1 的方式生成

        Addr      net.Addr // 连接地址
        Permanent bool  // 是否是持久连接

        conn       net.Conn
        state      ConnState // 记录该连接的状态
        stateMtx   sync.RWMutex
        retryCount uint32   // 记录持久连接的失败重试次数,如果成功连接则归0
}


// Config holds the configuration options related to the connection manager.
type Config struct {
        // Listeners defines a slice of listeners for which the connection
        // manager will take ownership of and accept connections.  When a
        // connection is accepted, the OnAccept handler will be invoked with the
        // connection.  Since the connection manager takes ownership of these
        // listeners, they will be closed when the connection manager is
        // stopped.
        //
        // This field will not have any effect if the OnAccept field is not
        // also specified.  It may be nil if the caller does not wish to listen
        // for incoming connections.
        Listeners []net.Listener

        // OnAccept is a callback that is fired when an inbound connection is
        // accepted.  It is the caller's responsibility to close the connection.
        // Failure to close the connection will result in the connection manager
        // believing the connection is still active and thus have undesirable
        // side effects such as still counting toward maximum connection limits.
        //
        // This field will not have any effect if the Listeners field is not
        // also specified since there couldn't possibly be any accepted
        // connections in that case.
        OnAccept func(net.Conn)

        // TargetOutbound is the number of outbound network connections to
        // maintain. Defaults to 8.
        TargetOutbound uint32

        // RetryDuration is the duration to wait before retrying connection
        // requests. Defaults to 5s.
        RetryDuration time.Duration

        // OnConnection is a callback that is fired when a new outbound
        // connection is established.
        OnConnection func(*ConnReq, net.Conn)

        // OnDisconnection is a callback that is fired when an outbound
        // connection is disconnected.
        OnDisconnection func(*ConnReq)

        // GetNewAddress is a way to get an address to make a network connection
        // to.  If nil, no new connections will be made automatically.
        GetNewAddress func() (net.Addr, error)

        // Dial connects to the address on the named network. It cannot be nil.
        Dial func(net.Addr) (net.Conn, error)
}

1.2 主要方法

1.2.1 start

1. go connHandler()
   启动处理连接的goroutine
2. go listenHandler()
   启动config里注册的listeners
3. go NewConnReq()

1.2.2 connHandler

pending map: 记录pending状态的连接信息
conns map : 记录连接状态的连接信息

for/select:
1. req := <-cm.requests:
   1. registerPending  表示 有待发生待连接请求
      如何处理:
      1.记录该请求到一个pending map中
   2. handleConnected  表示 连接建立
      如何处理:
      1.确保在pending map中添加过该连接
      2.pengding map删除条目, conns map中添加连接条目
      3.调用manager config配置的OnConnection方法

   3. handleDisconnected 表示 连接断开
      如何处理:
      1.确保在pending或者conns map中添加过该连接,并删除相应条目
      2.调用manager config配置的OnDisconnection方法
      3.根据 该断开的消息 是否需要重试分开处理
        1. 不需要的话,更新状态就结束
        2. 需要的话,在一定条件下将连接加到pending map里,然后调用handleFailedConn
   4. handleFailed 表示 失败情况
      1.确保在pending map中添加过该连接
      2.更新连接状态,然后调用handleFailedConn

2. <-cm.quit
   退出

1.2.3 handleFailedConn

该方法用来处理连接断开或者其他连接失败的情况
如果连接是持久连接,就在等待一段时间后尝试重连
如果不是,就建立一个新的连接,当重试的次数超过最大值后,那就等待一段时间再重新建立新连接。

1.2.4 listenHandler

该方法等待连接,然后调用config里的OnAccept来处理连接

1.2.5 NewConnReq

该方法创建一个新连接,连接到相应的地址。
具体逻辑:
连接数connReqCount+1
发送registerPending消息(由connHandler接收处理)
connHandler处理完register后,调用config的GetNewAddress方法获取新的地址addr
如果获取失败,发送handleFailed方法(由connHandler接收处理)
获取addr成功后,调用connect方法来获取连接

1.2.6 Connect

如果(根据连接id判断)该地址是个新连接,那么设置其id,然后注册到pending map连接里。
调用config里的Dial方法,连接到addr, 如果成功则发送handleConnected方法, 失败则发送handleFailed方法到cm.requests, 由connHandler处理

1.2.7 Disconnect

发送handleDisconnected消息给cm.requests

1.2.8 Stop

该方法先将config里的listeners调用close()
在调用close(cm.quit)发送退出消息告知各个goroutine

1.3 消息传递简图

只有一个cm.requests channel,通过传递不同的msg来让connhandler处理,整体还是比较简明清晰,故不作图了。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK