wmproxy

wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 静态文件服务器,四层TCP/UDP转发,七层负载均衡,内网穿透,后续将实现websocket代理等,会将实现过程分享出来,感兴趣的可以一起造个轮子

项目地址

国内: https://gitee.com/tickbh/wmproxy

github: https://github.com/tickbh/wmproxy

项目设计目标

针对有一些应用场景需要将TCP转成websocket的,就比如旧的客户端或者旧的服务端比较不合适进行改造,但是又需要借助阿里的全站加速DCDN等这类服务或者其它可能需要特定浏览器协议的情况下,需要进行协议的转化而服务。

Tcp转Websocket

流程图

以下展示Tcp转Websocket的流程图,就纯粹的Tcp客户端在不经过任何源码修改的情况下成功连接websocket服务端

flowchart TD
A[tcp客户端] -->|连接服务| B[服务节点]
B -->|服务转化| C[websocket客户端]
C -->|连接服务| D[websocket服务端]

比较适合原生客户端,又不想引入第三方库,又能在需要的时候直接使用websocket来做配合。

源码实现

实现源码在stream_to_ws

/// 将tcp的流量转化成websocket的流量
pub struct StreamToWs<T: AsyncRead + AsyncWrite + Unpin> {
url: Url,
io: T,
}
  • 需要传入的参数为原生的tcp,此处tcp是具备异步读异步写功能的虚拟tcp
  • 传入连接websocket的url地址,可以连接到websocket的服务端地址

定义回调类:

struct Operate {
/// 将tcp来的数据流转发到websocket
stream_sender: Sender<Vec<u8>>,
/// 从websocket那接收信息
receiver: Option<Receiver<OwnedMessage>>,
}
  • stream_sender将数据进行发送到websocket中
  • receiver从websocket中获取信息流

核心转发逻辑:

pub async fn copy_bidirectional(self) -> ProtResult<()> {
let (ws_sender, ws_receiver) = channel::<OwnedMessage>(10);
let (stream_sender, stream_receiver) = channel::<Vec<u8>>(10);
let url = self.url;
tokio::spawn(async move {
if let Ok(mut client) = Client::builder().url(url).unwrap().connect().await {
client.set_callback_ws(Box::new(Operate {
stream_sender,
receiver: Some(ws_receiver),
}));
let _e = client.wait_ws_operate().await;
}
});
Self::bind(self.io, ws_sender, stream_receiver).await?;
Ok(())
}

创建两对发送接收对分别为OwnedMessage及Vec<u8>来进行双向绑定,并在协程中发起对websocket的连接请求。更多的逻辑请查看源码。

测试demo

示例文件ws_stw,当下监听8082的流量并将其转发到8081的websocket服务上,测试借助websocat做测试服务端

  • cargo run --example ws_stw 启动转发监听8082
  • websocat -s 8081 监听8081
  • telnet 127.0.0.1 8082 手动建立8082的端口

成功测试转发

Websocket转Tcp

流程图

以下展示Websocket转Tcp的流程图,通常由浏览器环境中发起(因为浏览器的标准全双工就是websocket)。然后服务器这边由TCP的方案

flowchart TD
A[websocket客户端] -->|连接服务| B[服务节点]
B -->|服务转化| C[tcp客户端]
C -->|连接服务| D[tcp服务端]

比较适合原生服务端,又不想引入第三方库,又能兼容TCP及websocket协议,适合在这个做个中间层。

源码实现

实现源码在ws_to_stream

/// 将websocket的流量转化成的tcp流量
pub struct WsToStream<T: AsyncRead + AsyncWrite + Unpin + Send + 'static, A: ToSocketAddrs> {
addr: A,
io: T,
}
  • 需要传入的参数为原生的tcp,此处tcp是具备异步读异步写功能的虚拟tcp,其中'static表示io为一个类,而不是引用
  • 传入连接tcp的SocketAddr地址,可以连接到Tcp的服务端地址

定义回调类:

struct Operate {
/// 将tcp来的数据流转发到websocket
stream_sender: Sender<Vec<u8>>,
/// 从websocket那接收信息
receiver: Option<Receiver<OwnedMessage>>,
}
  • stream_sender将数据进行发送到websocket中
  • receiver从websocket中获取信息流

核心转发逻辑:

pub async fn copy_bidirectional(self) -> ProtResult<()> {
let (ws_sender, ws_receiver) = channel(10);
let (stream_sender, stream_receiver) = channel::<Vec<u8>>(10);
let stream = TcpStream::connect(self.addr).await?;
let io = self.io;
tokio::spawn(async move {
let mut server = Server::new(io, None);
server.set_callback_ws(Box::new(Operate {
stream_sender,
receiver: Some(ws_receiver),
}));
let e = server.incoming().await;
println!("close server ==== addr = {:?} e = {:?}", 0, e);
});
Self::bind(stream, ws_sender, stream_receiver).await?;
Ok(())
}

与tcp转websocket类似,但是此时是将io流量转成Server的处理函数。

测试demo

示例文件ws_wts,当下监听8082的流量并将其转发到8081的websocket服务上,测试借助websocat做测试服务端

新建测试TCP的监听,原样转发的测试代码:

#[tokio::main]
async fn main() -> std::io::Result<()> {
use tokio::{net::TcpListener, io::{AsyncReadExt, AsyncWriteExt}};
let tcp_listener = TcpListener::bind(format!("127.0.0.1:{}", 8082)).await?;
loop {
let mut stream = tcp_listener.accept().await?;
tokio::spawn(async move {
let mut buf = vec![0;20480];
loop {
if let Ok(size) = stream.0.read(&mut buf).await {
println!("receiver = {:?} size = {:?}", &buf[..size], size);
let _ = stream.0.write_all(b"from tcp:").await;
let _ = stream.0.write_all(&buf[..size]).await;
} else {
break;
}
}
});
}
}
  • cargo run --example tcp 监听8082的端口,收到数据原样转发
  • cargo run --example ws_wts 启动转发监听8081
  • websocat ws://127.0.0.1:8081 用websocket的方式连接到8081

成功测试转发

组合方案

当我们现存的网络方案为Tcp到Tcp或者为Websocket到Websocket而我们在中间的传输过程中如想利用DCDN做源地址保护,而他只支持Websocket,此时我们就可以利用数据的转化,将我们的数据包通过DCDN做转发:

flowchart TD
A[TCP客户端] -->|连接服务| B[服务节点]
B -->|转化成websocket通过加速| C[DCDN全站加速]
C -->|连接服务| E[服务节点]
E -->|转化成Tcp并串连到服务端| F[TCP服务端]

这样子我们就可以利用基础网络中的CDN或者DCDN等服务,又不用对旧的数据进行修改或者无法修改的程序就比如远程服务通过CDN进行加速等。

小结

协议的自由转化可以帮助我们创建更合适的网络环境,可以让运维更自由的构建系统。利用转化可以用好全站加速DCDN这类的功能,可以更好的保护源站,防止被DDOS攻击。

点击 [关注],[在看],[点赞] 是对作者最大的支持

41. 干货系列从零用Rust编写负载均衡及代理,websocket与tcp的映射,WS与TCP互转的更多相关文章

  1. Docker系列-(3) Docker-compose使用与负载均衡

    上一篇文章介绍了docker镜像的制作与发布,本文主要介绍实际docker工程部署中经常用到的docker-compose工具,以及docker的网络配置和负载均衡. Docker-compose介绍 ...

  2. Nginx服务器部署 负载均衡 反向代理

    Nginx服务器部署负载均衡反向代理 LVS Nginx HAProxy的优缺点 三种负载均衡器的优缺点说明如下: LVS的优点: 1.抗负载能力强.工作在第4层仅作分发之用,没有流量的产生,这个特点 ...

  3. [架构]辨析: 高可用 | 集群 | 主从 | 负载均衡 | 反向代理 | 中间件 | 微服务 | 容器 | 云原生 | DevOps | ...

    词汇集 灾备 冷备份 双机热备份 异地容灾备份 云备份 灾难演练 磁盘阵列(RAID) 故障切换 心跳监测 高可用 集群 主从复制(Master-Slave) 多集群横向扩容(master-clust ...

  4. 死磕nginx系列--使用upsync模块实现负载均衡

    问题描述 nginx reload是有一定损耗的,如果你使用的是长连接的话,那么当reload nginx时长连接所有的worker进程会进行优雅退出,并当该worker进程上的所有连接都释放时,进程 ...

  5. hbase源码系列(一)Balancer 负载均衡

    看源码很久了,终于开始动手写博客了,为什么是先写负载均衡呢,因为一个室友入职新公司了,然后他们遇到这方面的问题,某些机器的硬盘使用明显比别的机器要多,每次用hadoop做完负载均衡,很快又变回来了. ...

  6. 架构之Nginx(负载均衡/反向代理)

    Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器 ,也是一个 IMAP/POP3/SMTP 代理 服务器 . Nginx 是由 Igor Sys ...

  7. nginx负载均衡(反向代理)

    6,安装nginx 6.1 依赖库安装  要安装在root根目录里,不要装在虚拟环境里面 yum install gcc-c++ pcre pcre-devel zlib zlib-devel ope ...

  8. nginx域名转发 负载均衡 反向代理

    公司有三台机器在机房,因为IP不够用,肯定要分出来,所以要建立单IP 多域名的反向代理, 就是当请求www.abc.com 跳转到本机, 请求www.bbc.com 跳转到192.168.0.35 机 ...

  9. Nginx HTTP负载均衡/反向代理的相关参数测试

    原文地址:http://www.cnblogs.com/xiaochaohuashengmi/archive/2011/03/15/1984976.html 测试目的 (1)弄清楚HTTP Upstr ...

  10. nginx 负载均衡 反向代理

    nginx 通过方向代理实现负载均衡,负载均衡是大流量网站要做的措施,单从字面上的意思来理解为N台服务器平均分担负载,不会因为某一台服务器负载高宕机而影响用户访问网站,负载均衡至少需要三台服务器, 既 ...

随机推荐

  1. GitHub Actions 入门指南

    前言 GitHub Actions 可以构建一组自动化的工作流程,并提供了拉取请求.合并分支等事件来触发他们.一般成熟的开源项目会在每个版本发布时提供 releases ,它就是通过 Actions ...

  2. hci0 command 0xfc20 tx timeout(Realtek 8761B Chipset, Bluetooth 5.0)

    当前使用的Linux内核版本: 4.4.189 插上USB Bluetooth 5.0 Adapter后,dmesg显示如下log: [ 240.348480] usb 3-1.2: new full ...

  3. two-pointer 算法

    介绍 双指针算法是一种通过设置两个指针不断进行单向移动来解决问题的算法. 它包含两种形式: 两个指针分别指向不同的序列.比如:归并排序的合并过程. 两个指针指向同一个序列.比如:快速排序的划分过程. ...

  4. 手撕Vue-Router-知识储备

    前言 本文是手写Vue-Router的第一篇,主要是对Vue-Router的知识储备,为后面的手写做准备. 那么 VueRouter 怎么实现呢?要想实现 VueRouter,首先要知道 VueRou ...

  5. LangChain内幕指南

    1.概述 在人工智能迅速演进的时代,诸如Open AI的ChatGPT和Google的Bard等大型语言模型(LLMs)正彻底改变我们与技术互动的方式.这些技术巨头和SaaS公司正在竞相利用LLMs的 ...

  6. 地图选择器datav怎么使用?

    DataV 是一款基于阿里云的数据可视化产品,它提供了丰富的组件和功能,其中包括地图选择器.下面是一个详细的介绍: 1. 了解 DataV: - DataV 是一款强大的数据可视化工具,能够帮助用户将 ...

  7. 编辑linux服务启动命令(app-script.sh命令编写)

    #!/bin/sh# 注:这里可替换为你自己的执行程序,其他代码无需更改APP_NAME=app-biz.jar #使用说明,用来提示输入参数usage() { echo "Usage: s ...

  8. APP性能测试-客户端性能测试

    https://blog.csdn.net/xiaomaoxiao336368/article/details/83547318

  9. CentOS连接网络设置

    https://blog.csdn.net/tsundere_x/article/details/104263100  用这个 VMware提供了三种将虚拟网卡和物理网卡捆绑起来的方式,即桥接(Bri ...

  10. Win10笔记本开启热点让手机上网

    Win10开启热点让手机上网,笔记本电脑开启热点,笔记本电脑开启WiFi,手机连接笔记本电脑热点上网. 1.前提条件:笔记本电脑网线联网,笔记本电脑支持热点 2.胆子要大,不怕公司网管统计发现你的电脑 ...