将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通信端口的方法记录 的相关文章

  • 为什么省略分号会破坏这段代码?

    或者换句话说 为什么分号插入失败 导致下面的代码被破坏 function Foo Foo prototype bar function console log bar lt missing semicolon function Foo pr
  • 如何将值发布到输入框中?

    Intro I would like to get the current time after clicking at click and POST the value into input text box Note 假设包含引导样式表
  • 有没有办法动态更改 jqGrid 的单元格值?

    这个问题可能已经被问过很多次了 但我想知道是否可以动态更改 jqgrid 的单元格值 我基本上有一个网格 它通过 JSON 字符串加载数据 在特定列的某些行上 该值可能为 null 因此 预先知道哪个行 ID 是一个问题 然后能够将 nul
  • 将时间戳转换为一个数组

    在应用程序脚本 谷歌表中运行 我从 API 获取时间戳并返回此结果 1 6370611672429312E18 1 63706107263277082E18 我执行此代码并且工作正常 但问题不在数组中 我每次都需要它在数组中 const t
  • 更新存储在 chrome 扩展本地存储中的对象

    我正在开发一个 chrome 扩展 我将存储服务器发送的对象 例如 我将收到 命令 id 1 类型 A 大小 B 优先级 C 如果我有一个数据库 我会将其作为表中的一行插入commands 使用 chrome storage 我将这些对象的
  • JavaScript 相当于 Python 的参数化 string.format() 函数

    这是 Python 示例 gt gt gt Coordinates latitude longitude format latitude 37 24N longitude 115 81W Coordinates 37 24N 115 81W
  • Javascript 作为对象键的函数与块中标记函数之间的语法冲突

    假设您有一个支持两者的浏览器带标签的函数声明 https developer mozilla org en US docs Web JavaScript Reference Statements label Labeled function
  • onClick 处理程序在每个渲染周期触发

    我有这样的默认状态 this state selectedTab tab1 then 我的渲染方法是这样的 render const selectedTab this state return li tab1 li li tab2 li d
  • 通过 JavaScript 单击按钮/页面提交

    我想了解 asp net 框架如何知道何时单击了按钮 因此一旦收到请求 就会在服务器上触发其单击事件 我需要了解它是如何工作的 因为我想从 JavaScript 触发按钮的服务器单击事件 我能够从 JavaScript 执行页面提交 doc
  • 如何显示接下来的三个图像单击加载更多按钮

    我需要一个加载更多按钮来显示图像 页面加载时 我显示 3 个图像 单击 加载更多 按钮后 接下来的 3 个图像将显示在屏幕上 我尝试了下面的代码 但它不起作用 你能帮我解决这个问题吗 function item slice 0 2 show
  • jQuery:将文本区域滚动到给定位置

    我有一个包含很多文本的文本区域
  • ES6 模块范围

    我有代码 lib js var a a export var b b main js console log a a variable is not available in a global scope import b from lib
  • 了解 Document.createElement()

    我在用着GWT及其底层DOM能力 我基本上想要实现的是 Have a div包含一些文本的元素 其中一些文本将被包围span元素 span 元素可相互拖动并提供上下文菜单 New span元素可以由最终用户动态创建 它可能是这样的 在应用程
  • Google 地图 API - 地图未显示 - 没有错误

    我正在尝试将地图从 Google API 加载到 div 中 但是 地图未加载 并且没有输出任何错误 这是代码 google maps var geocoder map function codeAddress address geocod
  • React Redux - 在辅助函数中访问现有存储

    我试图在反应组件之外获取存储实例 存储状态 即在单独的辅助函数中 我有我的减速器 我的动作 我在最上面的组件中创建了一个商店 configStore js import createStore from redux import gener
  • 如何在 React Native 中使用相同的 Firebase 数据库在两个应用程序之间进行通信?

    我有两个不同的应用程序使用相同的实时数据库 在第一个应用程序中 我发送的订单包含一些要保存在数据库中的数据字段 在另一个应用程序中 我只添加一个侦听器 firebase database ref userOrder currentUser
  • Graphql 将多个查询合并(组合)为一个?

    我正在尝试使用 JavaScript 将多个 GraphQL 查询合并为一个查询 我正在寻找这样的东西 let query3 mergeQueries query1 query2 我们事先不知道哪些查询将被组合 假设我有这样的查询 输入查询
  • jQuery Mobile + Admob:轮换?

    我使用 jQuery Mobile 框架创建了一个移动应用程序 所有页面都在index php中加载 使用 div 在每个页面的页脚中 我添加了Admob代码 div div div
  • Java时区混乱

    我正在运行 Tomcat 应用程序 并且需要显示一些时间值 不幸的是 时间快到了 还有一个小时的休息时间 我调查了一下 发现我的默认时区被设置为 sun util calendar ZoneInfo id GMT 08 00 offset
  • JavaScript 阶乘防止无穷大

    我一直在 JavaScript 中使用这个函数来计算阶乘数 var f function factorial n if n 0 n 1 return 1 if f n gt 0 return f n return f n factorial

随机推荐

  • 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