Go – 在同一端口上监听多个协议(HTTP和RTMP)的Web服务器

huangapple go评论71阅读模式
英文:

Go - Webserver listening for multiple protocols (HTTP and RTMP) on the same port

问题

我正在尝试在我的Go Web应用程序中实现RTMP协议,但是我似乎无法找到同时处理HTTP和RTMP的解决方案。

想法是这样的:

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "Hello!")
	})

	http.HandleFunc("/rtmp", func(w http.ResponseWriter, r *http.Request) {
		// 在这里处理RTMP
	})

	fmt.Println("Starting web server")
	http.ListenAndServe(":8000", nil)
}

zhangpeihao/gortmp有一个很棒的RTMP模块,示例代码展示了如何通过监听TCP套接字来处理RTMP。但是如何在特定的端点上处理RTMP而不是使用第二个端口呢?

英文:

I'm trying to implement the RTMP protocol to along side my web application in Go, however I can't seem to figure out solution to handle both HTTP and and RTMP on the same port.

The idea would be something such as this.

package main

import (
	"fmt"
	"io"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		io.WriteString(w, "Hello!")
	})

	http.HandleFunc("/rtmp", func(w http.ResponseWriter, r *http.Request) {
		// RTMP handling here
	})

	fmt.Println("Starting web server")
	http.ListenAndServe(":8000", nil)
}

zhangpeihao/gortmp has a great RMTP module with an example that shows handling RTMP by listening on a TCP socket. However how can handle it on a specific endpoint rather then a second port?

答案1

得分: 0

避免将RTMPT转换为RTMP,并且不需要分叉其他模块,这是我最终通过读取第一个字节来解决的方法。完整的实现可以在这里找到。

func createLocalConnection(port string) *net.TCPConn {
    addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:"+port)
    if err != nil {
        panic(err)
    }
    conn, err := net.DialTCP("tcp", nil, addr)
    if err != nil {
        panic(err)
    }
    return conn
}

func proxyConnection(conn *net.TCPConn) {
    defer conn.Close()
    data := make([]byte, 1)
    n, err := conn.Read(data)
    if err != nil {
        fmt.Println(err)
        return
    }

    var proxyConn *net.TCPConn
    if data[0] == 0x03 { // RTMP第一个字节
        proxyConn = createLocalConnection(RTMPPort)
    } else {
        proxyConn = createLocalConnection(HTTPPort)
    }
    proxyConn.Write(data[:n])
    defer proxyConn.Close()

    // 请求循环
    go func() {
        for {
            data := make([]byte, 1024*1024)
            n, err := conn.Read(data)
            if err != nil {
                break
            }
            proxyConn.Write(data[:n])
        }
    }()

    // 响应循环
    for {
        data := make([]byte, 1024*1024)
        n, err := proxyConn.Read(data)
        if err != nil {
            break
        }
        conn.Write(data[:n])
    }
}

func main() {
    listener, err := net.ListenTCP("tcp", addr)
    if err != nil {
        panic(err)
    }

    for {
        conn, err := listener.AcceptTCP()
        if err != nil {
            fmt.Println(err)
            continue
        }

        go server.ProxyConnection(conn)
    }
}

这段代码通过读取第一个字节来判断连接的类型,如果是0x03,则创建一个本地RTMP连接,否则创建一个本地HTTP连接。然后,它将数据从客户端连接转发到代理连接,并将响应从代理连接转发回客户端连接。主函数中,它监听TCP连接并在接受到连接时启动代理连接的处理。

英文:

While wanting to avoid having to convert RTMPT to RTMP, and without having to fork other modules, this was my solution in the end by reading the first byte. Full implementation can be found here.

func createLocalConnection(port string) *net.TCPConn {
addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:"+port)
if err != nil {
panic(err)
}
conn, err := net.DialTCP("tcp", nil, addr)
if err != nil {
panic(err)
}
return conn
}
func proxyConnection(conn *net.TCPConn) {
defer conn.Close()
data := make([]byte, 1)
n, err := conn.Read(data)
if err != nil {
fmt.Println(err)
return
}
var proxyConn *net.TCPConn
if data[0] == 0x03 { // RTMP first byte.
proxyConn = createLocalConnection(RTMPPort)
} else {
proxyConn = createLocalConnection(HTTPPort)
}
proxyConn.Write(data[:n])
defer proxyConn.Close()
// Request loop
go func() {
for {
data := make([]byte, 1024*1024)
n, err := conn.Read(data)
if err != nil {
break
}
proxyConn.Write(data[:n])
}
}()
// Response loop
for {
data := make([]byte, 1024*1024)
n, err := proxyConn.Read(data)
if err != nil {
break
}
conn.Write(data[:n])
}
}
func main() {
listener, err := net.ListenTCP("tcp", addr)
if err != nil {
panic(err)
}
for {
conn, err := listener.AcceptTCP()
if err != nil {
fmt.Println(err)
continue
}
go server.ProxyConnection(conn)
}
}

huangapple
  • 本文由 发表于 2016年10月31日 11:04:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/40336038.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定