Skip to content

第四章:核心流程分析

先前在第二章的启动服务小节中,已经简要介绍了 frp 服务的部署与启动流程。 本章中,我们将把注意力放在 frp 服务的核心流程上——建立连接并进行数据传输, 这也是 frp 服务的根本目的。

为了方便理解,下面是本人用 draw.io 绘制的 frp 工作流程图:

workflow

我们将关注重心放在 frps 和 frpc 之间服务的建立,可以看到二者间有两条重要的通道:

  • msgTunnel:控制消息传输隧道,用于处理消息控制传输而非实际数据转发
    • 定时向服务器发送心跳包以保持连接
    • 当用户访问服务器时,检查是否启动 dataTunnel
    • 进行 token 验证,以保证连接安全
  • dataTunnel:数据传输隧道,用于数据转发(外部请求->frps->frpc->内网服务)

通过 frp 的转发,外部用户就能访问内网的服务,实现内网穿透的效果。

下面分别从 frps 和 frpc 两个角度来详细介绍这两个通道的建立过程。因为函数调用深度较大, 并且实现细节较多(涉及到各种协议的兼容以及错误处理),所以这里不直接展示源码, 而是通过自己绘制的时序图来展示 frps 和 frpc 之间的通信过程。

frps

frps

可以看到,frps 作为服务器端,主要通过 Server 类的 HandleListener() 方法来监听客户端的连接请求。

如果检测到有新的连接请求,用 handleConnection() 方法来处理, 调用 RegisterControl() 方法来注册控制通道,创建一个 Control 实例 ctl

ctl 对象用 worker() 方法建立控制通道和数据通道,其中控制通道用于处理消息传输,

frpc

frpc

对于 frpc 客户端,主要通过 Server 类的 Run() 方法来建立与服务器的连接。

首先通过 loginUntilSuccess() 不断重试直到登录成功,然后调用 login() 方法来登录服务器。

登录成功后,调用 NewControl() 方法来创建一个 Control 实例 ctl。该实例调用 worker() 方法建立控制通道和数据通道。 worker()方法中的具体流程和 frps 类似,但实现细节不同,尤其是对心跳包的处理,这在后面的章节中会详细介绍。