网站首页 > 开源技术 正文
在本站开启支持 QUIC 的方法与配置后,主观感觉从国内访问快了很多。看了一下Chrome的timing, 大部分建立连接都能够做到0-RTT:
既然这样,顺手实现一个基于QUIC的http代理,把平时查资料时使用的网络也顺带加速一下。(对了,前两天看到Google发布了Outline, 看来这项运动从来都不缺少运动员哪……)
http 代理原理
http 代理处理http和https请求的方式有所不同。对于http请求:
浏览器与代理服务器建立TCP连接后,将http请求发送给代理服务器。
代理服务器将http请求发送给目标服务器。
代理服务器获取到相应结果以后,将结果发送给浏览器。
这里有一个细节需要注意,浏览器向代理服务器发送的http请求URI与直接访问有所不同。
浏览器直接访问 GET http://www.yahoo.com
的http请求格式为:
GET / HTTP/1.1 User-Agent: Quic-Proxy ...
而向代理服务器发送的http请求格式为:
GET http://www.yahoo.com HTTP/1.1 User-Agent: Quic-Proxy ...
也就是浏览器想代理服务器发送的http请求URI中包含了scheme和host,目的是为了让代理服务器知道这个代理请求要访问的目标服务器地址。
对于https请求,一般是通过CONNECT
建立隧道:
浏览器向代理服务器建立TCP连接,发送
CONNECT
请求。代理服务器根据
CONNECT
请求中包含的host信息,向目标服务器建立TCP连接,然后向浏览器返回200
连接成功的响应。这时代理服务器同时维持着连接浏览器和目标服务器的TCP连接。
从浏览器的角度看,相当于建立了一条直连目标服务器的TCP隧道。然后直接在该隧道上进行TLS握手,发送http请求即可实现访问目标服务器的目的。
QUIC Proxy的设计与实现
QUIC PROXY 部署结构图
QUIC Proxy的部署结构与上面http代理原理稍微有所不同。主要区别是增加了qpclient
。主要原因是应用程序与代理服务器支架的请求是明文传输(http请求代理是全明文,https请求代理时的CONNECT头会泄露目标服务器信息)。我们是要隐私的人(虽然小扎可能并不care),因此,在应用程序与qpserver
之间加了一个qpclient
,之间使用QUIC
作为传输层。
实现
QUIC Proxy使用Go实现,猴急的同学可以直接到github看源码:Quic Proxy, a http/https proxy using QUIC as transport layer.
代码比较简单,基于标准库的http.Server
根据http代理的原理进行了一点http请求的修改。然后,因为qpclient
和qpserver
之间使用QUIC作为transport,而QUIC上的每一个connection都是可以多路复用(multiplexing)的,因此,对于qpserver
需要自己实现一个传入http.Server的listener:
type QuicListener struct { quic.Listener chAcceptConn chan *AcceptConn } type AcceptConn struct { conn net.Conn err error } func NewQuicListener(l quic.Listener) *QuicListener { ql := &QuicListener{ Listener: l, chAcceptConn: make(chan *AcceptConn, 1), } go ql.doAccept() return ql } func (ql *QuicListener) doAccept() { for { sess, err := ql.Listener.Accept() if err != nil { log.Error("accept session failed:%v", err) continue } log.Info("accept a session") go func(sess quic.Session) { for { stream, err := sess.AcceptStream() if err != nil { log.Error("accept stream failed:%v", err) sess.Close(err) return } log.Info("accept stream %v", stream.StreamID()) ql.chAcceptConn <- &AcceptConn{ conn: &QuicStream{sess: sess, Stream: stream}, err: nil, } } }(sess) } } func (ql *QuicListener) Accept() (net.Conn, error) { ac := <-ql.chAcceptConn return ac.conn, ac.err }
同样的,qpclient
向qpserver
建立连接也需要考虑到多路复用的问题,实现实现一个基于QUIC的dialer:
type QuicStream struct { sess quic.Session quic.Stream } func (qs *QuicStream) LocalAddr() net.Addr { return qs.sess.LocalAddr() } func (qs *QuicStream) RemoteAddr() net.Addr { return qs.sess.RemoteAddr() } type QuicDialer struct { skipCertVerify bool sess quic.Session sync.Mutex } func NewQuicDialer(skipCertVerify bool) *QuicDialer { return &QuicDialer{ skipCertVerify: skipCertVerify, } } func (qd *QuicDialer) Dial(network, addr string) (net.Conn, error) { qd.Lock() defer qd.Unlock() if qd.sess == nil { sess, err := quic.DialAddr(addr, &tls.Config{InsecureSkipVerify: qd.skipCertVerify}, nil) if err != nil { log.Error("dial session failed:%v", err) return nil, err } qd.sess = sess } stream, err := qd.sess.OpenStreamSync() if err != nil { log.Info("[1/2] open stream from session no success:%v, try to open new session", err) qd.sess.Close(err) sess, err := quic.DialAddr(addr, &tls.Config{InsecureSkipVerify: true}, nil) if err != nil { log.Error("[2/2] dial new session failed:%v", err) return nil, err } qd.sess = sess stream, err = qd.sess.OpenStreamSync() if err != nil { log.Error("[2/2] open stream from new session failed:%v", err) return nil, err } log.Info("[2/2] open stream from new session OK") } log.Info("addr:%s, stream_id:%v", addr, stream.StreamID()) return &QuicStream{sess: qd.sess, Stream: stream}, nil }
好吧,我承认实现代码似乎在200行左右……但是,我们实现了一个client和一个server, 平均下来基本控制在100行左右,对吧……
部署
注:需要golang版本 >= 1.9
1. 在远程服务器上安装 qpserver
go get -u github.com/liudanking/quic-proxy/qpserver
2. 启动qpserver
:
qpserver -v -l :3443 -cert YOUR_CERT_FILA_PATH -key YOUR_KEY_FILE_PATH
3. 在本地安装 qpclient
go get -u github.com/liudanking/quic-proxy/qpclient
4. 启动 qpclient
:
qpclient -v -k -proxy http://YOUR_REMOTE_SERVER:3443 -l 127.0.0.1:18080
5. 设置应用程序代理:
以 Chrome with SwitchyOmega 为例:
猜你喜欢
- 2024-09-28 QUIC助力Snapchat提升用户体验(snapchat help)
- 2024-09-28 quic-tun:借助 QUIC 打造一个安全且快速的隧道-用于优化 TCP 传输
- 2024-09-28 IETF正式颁布HTTP/3 RFC文档:QUIC映射或加速网络转型
- 2024-09-28 Chrome Canary已整合支持实验性的QUIC与HTTP/3协议
- 2024-09-28 详解:什么是HTTP/3 和 QUIC 协议(can通讯协议详解)
- 2024-09-28 深入解析QUIC协议(协议解析程序)
- 2024-09-25 「专题速递」RTC云网端联合优化、QUIC协议的能力和实践
- 2024-09-25 QuicRun Fusion SE |更亲民的FOC一体动力系统
- 2024-09-25 HTTP/3和QUIC将带来重大机遇和挑战
- 2024-09-25 HTTP3/QUIC 性能测试与配套组件(http3/quic+性能测试与配套组件的区别)
你 发表评论:
欢迎- 03-26业务监控—一站式搭建jmeter+telegraf+influxdb+Grafana看板
- 03-2615个最好的性能测试工具(软件测试工程师必备)
- 03-26软件测试工程师必备技巧!(软件测试工程师入门教程)
- 03-26UE4基础知识总结(七)(ue4入门)
- 03-26Portkeys推出新款HDMI播放器:5.5英寸FHD屏幕,支持4K输入/输出
- 03-26数字时代的纯粹,HiFiMan HM-901S 播放器体验
- 03-26CBN丨Double 11 sales shows resilience in China’s consumption
- 03-26AKG K812简单听感(akgk812pro评测)
- 最近发表
-
- 业务监控—一站式搭建jmeter+telegraf+influxdb+Grafana看板
- 15个最好的性能测试工具(软件测试工程师必备)
- 软件测试工程师必备技巧!(软件测试工程师入门教程)
- UE4基础知识总结(七)(ue4入门)
- Portkeys推出新款HDMI播放器:5.5英寸FHD屏幕,支持4K输入/输出
- 数字时代的纯粹,HiFiMan HM-901S 播放器体验
- CBN丨Double 11 sales shows resilience in China’s consumption
- AKG K812简单听感(akgk812pro评测)
- 盘点索尼Walkman发展史,哪台播放器让你印象深刻
- LUXMAN力仕 DA-07X 解码器#发烧hifi
- 标签列表
-
- jdk (81)
- putty (66)
- rufus (78)
- 内网穿透 (89)
- okhttp (70)
- powertoys (74)
- windowsterminal (81)
- netcat (65)
- ghostscript (65)
- veracrypt (65)
- asp.netcore (70)
- wrk (67)
- aspose.words (80)
- itk (80)
- ajaxfileupload.js (66)
- sqlhelper (67)
- express.js (67)
- phpmailer (67)
- xjar (70)
- redisclient (78)
- wakeonlan (66)
- tinygo (85)
- startbbs (72)
- webftp (82)
- vsvim (79)
本文暂时没有评论,来添加一个吧(●'◡'●)