这里应该看一下 Service 的数据结构:
看上去似乎都是和连接管理相关的,这里需要结合功能文档说明看代码了,然而并没有在文档中看到确切的说明,所以只能回到代码中去,一般来说这个应该是一个枚举值,然后可选项都放在一起,所以我找到了:
这里有六种类型,但是似乎从代码上来看并不是一一对应的,所以还是需要再次看一下 Service 的数据结构,然后我根据自己的理解先认为大概可以分为三类:
- 端口管理
- 不同类型的连接管理
- 其他
这里从文档中看,作者似乎把 TCP/KCP/HTTP/HTTPS 作为不同的实现来写,这个可以理解,毕竟就常用的 http 来说,很多时候并不能简单得以 TCP 来处理,看完数据结构之后脑中应该有个印象了,下面就需要看看是怎么构造 Service 的。看着代码的时候,因为内容比较多,所以我就先挑着我感兴趣的部分:TCP 部分来进行了解先,也就是和 TCP 可能有关的都先看一遍:
我觉得这段应该是核心代码了,所以就着重得分析一下,这里有一个核心组件 mux
需要了解一下用法,然后再看一下 frpNet.WrapLogListener
这个玩意是什么。结果发现 mux
是作者自己写的一个 tool,这里就先暂且猜测是用来做连接多路复用用的吧,如果右面有需要再看看源码;然后是 WrapLogListener
,这个原来只是一个 Listener 的封装,看用法有点像是使用的继承?不过这是个 Wrapper 倒是毫无疑问的,猜测可能是记录连接的请求日志。
那看样子大体上的结构都看到了,可以返回看一下 run 里面真的运行的是啥了:
这里其实和前面的集中连接类型一一对应了,所以真实对应过来,这里只做了四种控制:
- NAT
- KCP
- Websocker
- TCP
这里我现在只关心 Line 11 中的 TCP,所以其他都不看了先。
在连接处理的地方用到了一个新东西,但是不是必须的,所以我直接看下面一个:dealFn
,对于上面的 fmux 是一个开源的 connection multiplexing library,后面应该需要对他进行一个了解的,但是这里是忽略的,所以来看看 dealFn
:
这里发现连接处理的第一步居然是先读取一个 msg.Message
,通读代码之后发现原来作者自己定义了 Client 和 Server 端的通讯规则,服务端和客户端是通过 json 数据进行通信的,传输协议如下:
- 第 1 个字节标识
Message
的类型 - 第 2-9 总共 8 个字节组成一个 int64 数值,标识
Message
的长度 - 后续 length 个字节标识
Message
的内容 - 通过 1 中的类型构造结构体,然后通过 3 中的内容反序列化 JSON,这样就得到了 Client 的数据
获得 Message
之后就需要根据类型进行不同的处理,所有的类型有:
从处理函数上来看,这里只支持其中的 3 种类型,为啥呢?因为这里一个新建连接的处理函数的,所以支持的消息类型就只有:
- Login
- NewWorkConn
- NewVisitorConn
这里就先跟踪一下登录的吧:
这里的登录过程主要做这么几件事:
- 检查客户端和服务端的版本兼容性
- 校验认证信息
- 确认 RunId
- 添加客户端连接到服务的连接管理中
- 设置状态变量
这里我觉得比较有价值的片段应该是 4,所以详细得来看一下:
这个 Control 有什么用,然后后面还调用了 Start,Connection 需要 start?需要 Start 是因为有什么定时任务之类的?继续分析一下,结果进去后看又是一个结构体初始化函数:
还不如直接看 Start:
卧槽,有种要说中的感觉,从 Line 1 的 comment 中我们知道了通信模型,关键是 working 是如何 work 的,这里有好几个 goroutine 被启动
- ctl.writer() 从 send channel 中读取要写的数据并且写出去
- ctl.reader() 从 connect 中读取数据,写入 recv channel,不做其他处理
- ctl.manager() 从 recv channel 中读取数据并且处理之后谢往 send channel
- ctl.stoper() 等待 connect 结束,做一些善后工作
所以这里的 ctl.manager() 是核心组件,ctl.stoper() 是重要组件。这里有一个很重要的点就是 Server 向 Client 发送了一个 ReqWorkConn 的消息,但是 Client 怎么响应还不知道,这个可以在看 Client 端代码的时候详读。我觉得就先看 ctl.manager 好了:
这里可以看到是存在心跳访问的,应该就是 Ping/Pong 了吧,然后数据操作并不在这里执行,所以前面的说错了,下面就需要去找找数据管理是在哪里执行。
Server 端的主体就先到了,这里的 manager 是关键位置,相信在读 client 端代码的时候会时不时和这里对应起来。