将websocket通信端口代理到TCP通信端口的方法记录

2023-10-27

1、websocketproxy代理服务基于go语言实现

 

2、功能描述:Proxy of gateway. Websockt transfer TCP protocol.

(1) Websocket -> TCP
(2)TCP -> Websocket

即:实现将websocket通信代理到TCP通信,实现web客户端通过websocket通信与后台TCP服务器之间的数据交互。

 

3、使用方法:讲go源码编译出可执行程序:

 

4、查看websocketproxy代理服务进程是否启动 及 启动代理的方法:

(1)查看命令:ps -elf | grep websocketproxy

websocketproxy没有启动状态:

(2)启动websocketproxy进程:

./websocketproxy 按下enter会提示启动方法:

(3)启动websocketproxy进程命令:./websocketproxy -host=127.0.0.1:554 -port=8081

(4)另起一个终端,查看websocketproxy进程是否启动:ps -elf | grep websocketproxy

如下图:则说明websocketproxy进程已经启动:

或者使用命令: ./websocketproxy -host=127.0.0.1:554 -port=8081 &

将websocketproxy进程在后台运行:

(5)启动websocketproxy进程的命令行解释:./websocketproxy -host=127.0.0.1:554 -port=8081 &

1)host=127.0.0.1:台服后务器TCP通信的ip地址

2)554:  后台服务器TCP通信所监听的端口

3)port=8081:建立websocket所使用的端口号,如:ws://127.0.0.1:8081/tztek/test

4)&: 将该进程放在后台运行

5)其他说明:将websocket通信所使用的8081端口的消息代理到tcp通信的554端口,实现消息交互。

 

5、使用举例:

(1)功能:实现将websocket通信所使用的8081端口的消息代理到easydarwin流媒体服务器的tcp通信的554端口,实现web客户端和easydarwin流媒体服务器之间的消息交互。

(2)步骤:

1)下载并进入easydarwin流媒体服务应用程序所在文件夹(自备):

2) 查看easydarwin.ini配置文件信息,查询tcp通信端口号,vim easydarwin.ini:

查询tcp通信端口号为:554

  1 [http]
  2 port=10008
  3 default_username=admin
  4 default_password=admin
  5 
  6 [rtsp]
  7 port=554
  8 
  9 ; rtsp 超时时间,包括RTSP建立连接与数据收发。
 10 timeout=28800
 11 
 12 ; 是否使能gop cache。如果使能,服务器会缓存最后一个I帧以及其后的非I帧,以提高播放速度。但是可能在高并发的情况下带来内存压力。
 13 gop_cache_enable=1
 14 
 15 ; 是否使能推送的同事进行本地存储,使能后则可以进行录像查询与回放。
 16 save_stream_to_local=1
 17 
 18 ;easydarwin使用ffmpeg工具来进行存储。这里表示ffmpeg的可执行程序的路径
 19 ffmpeg_path=/usr/local/ffmpeg/bin/ffmpeg
 20 
 21 ;本地存储所将要保存的根目录。如果不存在,程序会尝试创建该目录。
 22 m3u8_dir_path=/home/xuwei/xuwei/record
 23 
 24 ;切片文件时长。本地存储时,将以该时间段为标准来生成ts文件(该时间+一个I帧间隔),单位秒
 25 ts_duration_second=10
 26 
 27 ;ffmpeg转码格式,比如可设置为-c:v copy -c:a copy,表示copy源格式;default表示使用ffmpeg内置的输出格式,可能需要转码
 28 /stream_265=default

3)启动easydarwin流媒体服务器:./easydarwin

如下:则启动成功

 

4)启动websocketproxy进程,将websocket通信所使用的8081端口的消息代理到easydarwin流媒体服务器的tcp通信的554端口,实现web客户端和easydarwin流媒体服务器之间的消息交互。

命令:./websocketproxy -host=127.0.0.1:554 -port=8081 &

5)编写websocket通信demo,测试代理是否成功:

websocket通信demo源码如下:

<!DOCTYPE HTML>
<html>

<head>
  <meta charset="utf-8">
  <title>websocket通信代理测试</title>

  <script type="text/javascript">
    function WebSocketTest() {
      //1.创建websocket客户端
      var wsServer = 'ws://127.0.0.1:8081/tztek/test';
      var limitConnect = 30; // 断线重连次数
      var timeConnect = 0;
      webSocketInit(wsServer);

      //socket初始化
      function webSocketInit(service) {
        var ws = new WebSocket(service);
        console.log("ws == ", ws);
        ws.onopen = function () {
          console.log("已连接TCP服务器");
        };
        ws.onmessage = function (msg) {
          console.log(msg.data  );
        };
        ws.onclose = function () {
          console.log('服务器已经断开');
          reconnect(service);
        };

        // 重连
        function reconnect(service) {
          if (limitConnect > 0) {
            limitConnect--;
            timeConnect++;
            console.log("第" + timeConnect + "次重连");
            // 进行重连
            setTimeout(function () {
              webSocketInit(service);
            }, 2000);

          } else {
            console.log("TCP连接已超时");
          }
        }

        // 心跳 * 回应
        // setInterval(function () {
        //   ws.send('xw_ping');
        // }, 1000 * 5);

      }

    }
  </script>

</head>

<body>

  <div id="sse">
    <a href="javascript:WebSocketTest()">运行 WebSocket</a>
  </div>

</body>

</html>

测试现象及结果:

结果表明:

a.建立websocket成功

b.代理服务端口转发成功(未放截图),现象描述:web客户端能通过8081端口和easydarwin流媒体服务器之间实现数据交互。

6)其他:本web客户端测试demo,还具备断线重连 + 心跳检测(保活)功能:

a.关闭服务进程:killall websocketproxy

b.重启websocketproxy服务进程:./websocketproxy -host=127.0.0.1:554 -port=8081 &

 

 

 

6、附WebsocketProxy.go代理服务源码

package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"runtime"

	"github.com/gorilla/websocket"
)

var g_tcpAddress string

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

func copyW2TWorker(dst net.Conn, src *websocket.Conn, doneCh chan<- bool) {
	defer func() {
		doneCh <- true
	}()

	for {
		_, message, err := src.ReadMessage()
		if err != nil {
			//log.Fatalln("[copyW2TWorker] websocket ReadMessage failed! err=%v", err)
			return
		}

		log.Printf("type=%d recv=%s", websocket.BinaryMessage, message)
		_, err = dst.Write([]byte(message))
		if err != nil {
			//log.Fatalln("[copyW2TWorker] tcp Write failed! err=%v", err)
			return
		}
	}
}

func copyT2WWorker(dst *websocket.Conn, src net.Conn, doneCh chan<- bool) {
	defer func() {
		doneCh <- true
	}()

	buff := make([]byte, 1024)
	for {
		n, err := src.Read(buff)
		if err != nil {
		//	log.Fatalln("[copyT2WWorker] tcp Read failed! err=%v", err)
			return
		}

		log.Printf("T2W type = %d read message = %s\n", websocket.BinaryMessage, string(buff[:n]))
		err = dst.WriteMessage(websocket.BinaryMessage, buff[:n])
		if err != nil {
			//log.Fatalln("[copyT2WWorker] websocket WriteMessage failed! err=%v", err)
			return
		}
	}
}

func relayHandler(w http.ResponseWriter, r *http.Request) {
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade:", err)
		return
	}

	conn, err := net.Dial("tcp", g_tcpAddress)
	if err != nil {
		log.Printf("[ERROR] %v host [%v]\n", err, g_tcpAddress)
		return
	}

	doneCh := make(chan bool)

	go copyW2TWorker(conn, ws, doneCh)
	go copyT2WWorker(ws, conn, doneCh)

	<-doneCh
	conn.Close()
	ws.Close()
	<-doneCh
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage: %s -host=ip:port -port=listen_port [option]\noption:\n", os.Args[0])
	flag.PrintDefaults()
}

func Init() (string, int, string, string, error) {
	var host string
	var port int
	var certFile string
	var keyFile string

	flag.StringVar(&host, "host", "", "Object server host(ip:port) for proxy")
	flag.IntVar(&port, "port", 0, "Port to listen on.")
	flag.StringVar(&certFile, "tlscert", "", "TLS cert file path")
	flag.StringVar(&keyFile, "tlskey", "", "TLS key file path")
	flag.Usage = usage
	flag.Parse()

	if host == "" || port == 0 {
		return host, port, certFile, keyFile, fmt.Errorf("Not enough args!")
	}

	return host, port, certFile, keyFile, nil
}

func main() {
	runtime.GOMAXPROCS(1) //设置cpu的核的数量,从而实现高并发

	tcpAddress, port, certFile, keyFile, err := Init()
	if err != nil {
		usage()
		os.Exit(1)
	}

	g_tcpAddress = tcpAddress

	portString := fmt.Sprintf(":%d", port)
	log.Printf("[INFO] starting server on port %d to proxy server [%s]\n", port, tcpAddress)

	if certFile != "" && keyFile != "" {
		err = http.ListenAndServeTLS(portString, certFile, keyFile, nil)
	} else {
		http.HandleFunc("/tztek/wstest", relayHandler)
		err = http.ListenAndServe(portString, nil)
	}
	if err != nil {
		log.Fatal(err)
	}
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将websocket通信端口代理到TCP通信端口的方法记录 的相关文章

  • Chart.js 在初始化时设置活动段

    我正在使用 Chart js v2 并且尝试在加载图表时模拟圆环图上某个段的 悬停状态 因此看起来有一个部分已突出显示 我已经搜索和梳理了代码一天 但找不到一个好的方法来做到这一点 提前致谢 设置片段的悬停样式有点令人困惑 因为它没有真正记
  • 渲染货币和符号并与来自不同单元格的数据相结合

    我正在使用最新的 jQuery DataTables v1 10 7 我正在尝试将数字解析为以下格式 239 90 USD 我可以使用此命令使货币正常工作 columns data Price render fn dataTable ren
  • 为什么我的淘汰单选按钮在另一个具有点击绑定的元素内时会失败?

    我有一个单选按钮列表 我想要点击 li 他们还检查单选按钮 这一切都有效 直到我放了一个name单选元素上的属性 然后我的代码停止工作 我的代码如下所示 ul li li ul li
  • 在新的 Google 协作平台 <嵌入 HTML> 中使用 localStorage 和 IndexedDB 不起作用

    我正在尝试将新的 Google 协作平台用于我开发的网页 但是 我在存储本地数据时遇到了问题 本地文件在 Windows 和 Apple safari chrome 中运行良好 从 Google 协作平台尝试一下 没有什么乐趣 此外 在 s
  • Chrome 中的性能问题

    我目前正在从事一个相对较大的项目 使用 AngularJs 构建 应用程序的一部分是一个表单 您可以向其中添加任意数量的页面 不幸的是 添加了很多不必要的垃圾 即表示表单模型的对象可能会变得非常大 在某些时候 Chrome 基本上无法处理它
  • 如何更改 Google Maps v3 API for Directions 中的开始和结束标记图像

    我使用 DirectionsRender 绘制了一条路线 但我不知道如何用我自己的标记替换通用的 Google 标记 我知道并在正常的谷歌地图情况下使用它 但发现很难用开始和结束的方向标记来做到这一点 如果这是一个愚蠢的问题 感谢您的任何建
  • 如何将内联 JavaScript 与 Express/Node.js 中动态生成的内容分开?

    对于具有几年 Web 开发经验但没有找到答案的人来说 这是一个有点菜鸟的问题程序员堆栈交换 or Google 我决定在这里问一下 我在用Express网络框架Node js 但这个问题并不特定于任何 Web 框架或编程语言 以下是从数据库
  • 摩卡 - Chai Karma“套件未定义”

    我对 jscript tdd 很陌生 遇到了问题 希望有人能告诉我我在做什么 在浏览器中运行测试 通过 HTML 文件 一切正常 通过节点和业力运行它们我得到以下异常 我想在 node js 主机的 karma 中使用 Mocha 和 Ch
  • 引导程序提前输入未填充承诺的响应

    我的引导程序预输入如下
  • Bootstrap按钮加载+Ajax

    我正在使用 Twitter Bootstrap 的按钮加载状态 http twitter github com bootstrap javascript html buttons http twitter github com bootst
  • 防止 iOS 键盘在 cordova 3.5 中滚动页面

    我正在使用 Cordova 3 5 和 jQuery mobile 构建 iOS 应用程序 我在大部分应用程序中禁用了滚动功能 但是 当我选择输入字段时 iOS 键盘会打开并向上滚动页面 我不想要这个功能 由于输入足够高 键盘不会覆盖它 我
  • 如何纠正流警告:解构(缺少注释)

    我正在编写一个小型 React Native 应用程序 并且正在尝试使用 Flow 但我无法在任何地方真正获得有关它的正确教程 我不断收到错误 destructuring Missing annotation 有关 station 这段代码
  • Angular - CSS - 自定义类型=文件输入,如何使用按钮而不是标签?

    我制作了一个类型为 file 的自定义输入字段 因为我不喜欢默认的输入字段 为了实现这一目标 我做了
  • 调整图像大小并将画布旋转 90 度

    这里有很多关于在 js 上使用画布旋转图像的主题 我阅读了其中的大部分内容 但无法找到解决我的问题的方法 我正在接收任何分辨率的图像 来自上传组件 我将其大小调整为 1024x768 如下所示 var canvas document cre
  • Javascript split 不是一个函数

    嘿朋友们 我正在使用 javascript sdk 通过 jQuery facebook 多朋友选择器在用户朋友墙上发布信息 但是我收到此错误friendId split 不是函数 这是我的代码 function recommendToFr
  • 在 JavaScript 循环之外声明变量可以提高速度和内存?

    C 也有类似的问题 但我们没有看到 JavaScript 的任何问题 在循环内声明变量是否可以接受 假设循环有 200 次迭代 使用样本 2 相对于样本 1 是否有性能要求 内存和速度 我们使用 jQuery 来循环 它提高了我们将 var
  • 在 Shopify 商店中嵌入 Vue 组件

    在产品页面中 我尝试显示自定义 Vue 组件 为简洁起见 该组件根据给定的产品 ID 显示 Firebase 数据库中的一些信息 我最初尝试将其制作为 Shopify 应用程序 以便我可以访问他们的 API 我实现了 OAuth 并且可以检
  • Javascript - 水波纹效果

    我需要 JS 上的脚本 它将以 水波纹 样式更改 images html 抱歉 6MB GIF 文件 http fcuunited ru temp listening2 gif http fcunited ru temp listening
  • 从 FileReader 设置背景图像样式

    我正在寻找一种解决方案 允许我从文件上传输入中获取文件并通过设置 document body style backgroundImage 来预览它 以下代码用于在 Image 元素中显示预览 function setImage id tar
  • 如何在react-highcharts中使用图表工具提示格式化程序?

    如何使用图表工具提示格式化程序 我正在使用高图表的反应包装器 我有这样的配置 const CHART CONFIG tooltip formatter tooltip gt var s b this x b each this points

随机推荐

  • STL之equal函数

    template
  • Golang fasthttp 为什么你这么优秀

    最近 需要使用 http client 发送数据 网上都说 fasthttp 据说是目前golang性能最好的http库 相对于自带的net http 性能说是有10倍的提升 参考 https studygolang com article
  • Firefly AIO-3399ProC开发板刷ubuntu系统 安装rknntoolkit 1.6.0 + tensorflow 2.0 + pytorch 1.5.0

    AIO 3399Pro刷ubuntu系统同时配置rknntoolkit 1 6 0 环境 由于本人所做项目需要将轻量级的深度学习算法进行部署 故前些日子购买了核心板为RK3399的深度学习开发板 用起来固然没有NVIDIA的jetson开发
  • chatgpt赋能python:建立Python开发环境的详细指南

    建立Python开发环境的详细指南 对于想要成为一名Python开发工程师的人来说 建立一个良好的开发环境是非常重要的 在安装和配置Python的过程中 您可能会遇到许多问题 并可能会出现错误 但是 请不要担心 因为这篇文章提供了一份详细的
  • keepalived高可用实战与Nginx负载均衡视频教程

    微技术 学无止境 一个专注于分享各种教程 技术 文章 分享等资源 为大家的工作 学习 提供便利 前言 大家好 我是微技术 今天给大家分享一款推荐负载均衡的学习教程 让你架构技术更加提高一点 更多深入一些技术 视频教程 keepalived
  • android 动态数据抓取,mitmproxy抓取Keep热门动态-安卓APP抓包爬虫案例

    使用mitmproxy来抓取Keep首页热门动态 鳄鱼君也是费了一天的时间去测试 在这里需要提醒大家抓包不要使用Android系统超过7 0的手机 Android系统越高手机越安全 而我们的抓包很显然是不允许的 这就是为什么你在配置了手机证
  • ajax与javascript,jquery, jquery UI

    ajax就是使用javascript语言实现的一种与服务器异步通信的方式 其核心是xmlhttprequest 像谷歌地图这种应用 如果点击某个点 需要重新刷新页面的话 用户体验很不好 这样的场所使用ajax就非常的方便 jQuery是一个
  • css媒体查询改变上边距,html - CSS宽度和边距不会与媒体查询相加

    我正在建立一个博客布局 目标是以窗口为中心 以最大宽度和最小边距为窗口 以内容为中心 我使用max width和媒体查询的组合来设置一定阈值的边距 我试着把max width和fixedmargin left和margin right放在一
  • go get & go mod找不到包问题解决

    问题一 今天在云虚机中遇到了go get执行报错的问题 报错内容如下 试了ping百度正常 说明不是DNS的问题 执行go mod tidy同样报错 最后找到问题 将GOPROXY由https proxy golang org改为了http
  • SpringBoot:自动装配提速设计

    名词约定 配置类 指使用了 Configuration Component ComponentScan Import ImportResource Bean的类 SpringBoot的设计思想就是通过一个配置类导入多个项目范围内适用的配置类
  • 《零基础入门学习Python》第087讲:Pygame:播放声音和音效

    这节课我们来谈谈 Pygame 中的 播放声音和音效 因为几乎没有任何游戏是一声不吭的 多重的感官体验更能刺激玩家的神经 没有声音的游戏就好比 不蘸番茄的薯条 尽管如此 Pygame 对于声音的处理并不是太理想 我说的是如果你想用 Pyga
  • 线性代数学习笔记——行列式的性质及拉普拉斯定理——11. 拉普拉斯定理

    这节如果不看教学视频而只看PPT的话 很难理解 这充分说明了老师的重要性 1 拉普拉斯 Laplace定理 2 基本结论 三角 对角分块矩阵行列式的计算 3 拉普拉斯定理的应用示例 求行列式 4 分块矩阵的逆的求解
  • ansible批量添加用户账户密码

    一 批量添加root用户以及密码 首先批量添加root 账号密码 不用ssh copy id root ip地址 因为如果ip比较多的情况下 ssh脚本添加会特别的麻烦 步骤1 首先要配置ansible清单 远程主机的密码这里为 12345
  • Idea上传已有项目到git

    开发经常遇到的问题是开发初期没有建立GIT仓库 开发一段时间后 需要将已有代码上传到Git 怎么将已有项目与新建的Git仓库相关联呢 借助Idea可以轻松实现 1 首先使用Git命令行 git clone XXXXX git 将项目下载 2
  • JAVA控制台输出格式

    public class PrintFormat public static void main String args Console print format System out printf format args format为指
  • Python键鼠操作自动化库PyAutoGUI简介

    PyAutoGUI是一个Python语言的键鼠自动化库 简单来说和按键精灵的功能一样 但是因为是Python的类库 所以可以使用Python代码配合一些其他类库完成更加强大的功能 下面让我为大家介绍一下吧 安装 从pip安装即可 pip i
  • 【threejs 】添加标签和射线

    three 添加标签 应用 上一篇文章我们说了世界坐标和屏幕坐标的准换那么有什么应用呢 应用 可以实现该效果 鼠标移动该模块的时候展示该模块的标签 或者可以常显 射线就是当鼠标移动到该模块该模块变化颜色 创建一个标签js文件作为封装的方法
  • 深入理解文字高度和行高的设置

    font size设置的是什么 line height设置的是什么 各种行高是怎么计算出来的 你真的知道吗 1 从font size讲起 说文字高度 当你按住鼠标左键选中一段文字的时候 这段文字背后会有一个颜色变化的区域 这个区域可以近似的
  • 零基础开发WIFI设备(esp8266)

    目录 前言 一 本例程实现功能 二 Core提供的TCP功能介绍 三 接线图 四 材料清单 五 完整代码 通过IP地址和服务器建立连接 代码运行结果 前言 shineblink core 开发板 简称Core 的库函数支持WIFI功能 所以
  • 将websocket通信端口代理到TCP通信端口的方法记录

    websocketproxy代理服务基于go语言实现 功能描述 Proxy of gateway Websockt transfer TCP protocol Websocket gt TCP TCP gt Websocket 即 实现将w