简介

先看下官方的介绍。

frp is a fast reverse proxy to help you expose a local server behind a NAT or firewall to the Internet. As of now, it supports TCP and UDP, as well as HTTP and HTTPS protocols, where requests can be forwarded to internal services by domain name. frp also has a P2P connect mode.

从官方文档了解,frp 是一个高性能的反向代理,将 NAT 或者防火墙内网的服务暴露在公网上。目前支持 TCP,UDP 和 HTTP 等协议,并且支持 P2P 模式打洞。

就是说,frp 是一个帮你打通传输层协议的工具,对于外网的你来说访问内网服务就跟访问外网服务一样便捷。

该项目开始于 2016 年初,至今为止已发版到 v0.38.0,项目诞生到现在发版的频次不算高,star 数目前已过 5w + ,在 GitHub golang 的项目中 star 排名排第 7。

架构

image.png

frp 是典型的 C-S 架构。

内网可以直接访问公网,公网不能直接穿透到内网,需要一个工具来完成隧道打通。TCP 协议是双向的,只要连接建立了,就可以双向传输数据了。 frp 就是帮助我们打通了这样的一条传输隧道。

控制流

frpc 第一次连接到 frps 之后,这条连接会长期保持,作为控制流的连接通道。如果开启了多路复用,这条连接还是数据流的物理连接。

数据流

如果没有开启连接多路复用,当用户第一次连接 frps 的时候,frps 会通过控制流告诉 frpc 发起一条数据流连接,然后这条连接就会作为数据流连接进行服务。

几个经典的使用场景

ssh

希望登录内网的机器,可以将 ssh 的端口暴露在公网。frp 本身不关注 ssh 协议,所以登录的时候依然需要密钥登录或者是密码登录。

tcp

内网是典型的 tcp 服务,其实上面的 ssh 就是 tcp,配置好暴露在公网的端口即可。

udp

udp 没有严格意义上的连接概念,这里其实是 udp over tcp 来实现的。就是说 udp 的报文通过 tcp 来传输的,保证了传输的安全性和可靠性。

stcp

是一种特殊的模式,在 frps 不暴露端口,保证了安全,通过2 个 client 与 server 打通隧道。
image.png

sudp

sudp 与 stcp 类似,本质上算是复用了 stcp 的能力,利用 tcp 来传输 udp 的数据。这里多说一句,sudp 可以非常好的解决运营商 dns 劫持的问题,所以非常推荐大家在合适的场景使用 sudp。

源码结构

这里以 v0.38.0 版本为例,简单讲解一下代码的组织结构。其实 frp 的代码结构非常清晰,我读过很多开源项目,frp 的组织方式是让我最舒服的,项目的组织方式对我自己开发 golang 项目产生了深远的影响。

image.png

核心代码都在 client、server、pkg 和 cmd 里。从命名就可以看出各个 package 的作用,非常典型的 golang 项目风格。

阅读建议

建议拉取某个 release 版本,然后自己添加注释,并且同步到 GitHub。比如可以命名为 frp-v0.38.0 作为自己跟进阅读的记录。

总结

本文简单介绍了 frp 的项目,旨在作为一个入门,后续会更新更多源码分析的文章。

参考资料

https://github.com/fatedier/frp/tree/v0.38.0