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

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会提示启动方法:

将websocket通信端口代理到TCP通信端口的方法记录_第1张图片

(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

如下:则启动成功

将websocket通信端口代理到TCP通信端口的方法记录_第2张图片

将websocket通信端口代理到TCP通信端口的方法记录_第3张图片

 

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

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

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

websocket通信demo源码如下:





  
  websocket通信代理测试

  





  



测试现象及结果:

结果表明:

a.建立websocket成功

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

将websocket通信端口代理到TCP通信端口的方法记录_第4张图片

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

a.关闭服务进程:killall websocketproxy

将websocket通信端口代理到TCP通信端口的方法记录_第5张图片

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

 

将websocket通信端口代理到TCP通信端口的方法记录_第6张图片

 

 

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)
	}
}

 

你可能感兴趣的:(流媒体,linux,golang,javascript)