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

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

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

问题

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

想法是这样的:

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "net/http"
  6. )
  7. func main() {
  8. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  9. io.WriteString(w, "Hello!")
  10. })
  11. http.HandleFunc("/rtmp", func(w http.ResponseWriter, r *http.Request) {
  12. // 在这里处理RTMP
  13. })
  14. fmt.Println("Starting web server")
  15. http.ListenAndServe(":8000", nil)
  16. }

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.

  1. package main
  2. import (
  3. "fmt"
  4. "io"
  5. "net/http"
  6. )
  7. func main() {
  8. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  9. io.WriteString(w, "Hello!")
  10. })
  11. http.HandleFunc("/rtmp", func(w http.ResponseWriter, r *http.Request) {
  12. // RTMP handling here
  13. })
  14. fmt.Println("Starting web server")
  15. http.ListenAndServe(":8000", nil)
  16. }

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,并且不需要分叉其他模块,这是我最终通过读取第一个字节来解决的方法。完整的实现可以在这里找到。

  1. func createLocalConnection(port string) *net.TCPConn {
  2. addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:"+port)
  3. if err != nil {
  4. panic(err)
  5. }
  6. conn, err := net.DialTCP("tcp", nil, addr)
  7. if err != nil {
  8. panic(err)
  9. }
  10. return conn
  11. }
  12. func proxyConnection(conn *net.TCPConn) {
  13. defer conn.Close()
  14. data := make([]byte, 1)
  15. n, err := conn.Read(data)
  16. if err != nil {
  17. fmt.Println(err)
  18. return
  19. }
  20. var proxyConn *net.TCPConn
  21. if data[0] == 0x03 { // RTMP第一个字节
  22. proxyConn = createLocalConnection(RTMPPort)
  23. } else {
  24. proxyConn = createLocalConnection(HTTPPort)
  25. }
  26. proxyConn.Write(data[:n])
  27. defer proxyConn.Close()
  28. // 请求循环
  29. go func() {
  30. for {
  31. data := make([]byte, 1024*1024)
  32. n, err := conn.Read(data)
  33. if err != nil {
  34. break
  35. }
  36. proxyConn.Write(data[:n])
  37. }
  38. }()
  39. // 响应循环
  40. for {
  41. data := make([]byte, 1024*1024)
  42. n, err := proxyConn.Read(data)
  43. if err != nil {
  44. break
  45. }
  46. conn.Write(data[:n])
  47. }
  48. }
  49. func main() {
  50. listener, err := net.ListenTCP("tcp", addr)
  51. if err != nil {
  52. panic(err)
  53. }
  54. for {
  55. conn, err := listener.AcceptTCP()
  56. if err != nil {
  57. fmt.Println(err)
  58. continue
  59. }
  60. go server.ProxyConnection(conn)
  61. }
  62. }

这段代码通过读取第一个字节来判断连接的类型,如果是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.

  1. func createLocalConnection(port string) *net.TCPConn {
  2. addr, err := net.ResolveTCPAddr("tcp", "127.0.0.1:"+port)
  3. if err != nil {
  4. panic(err)
  5. }
  6. conn, err := net.DialTCP("tcp", nil, addr)
  7. if err != nil {
  8. panic(err)
  9. }
  10. return conn
  11. }
  12. func proxyConnection(conn *net.TCPConn) {
  13. defer conn.Close()
  14. data := make([]byte, 1)
  15. n, err := conn.Read(data)
  16. if err != nil {
  17. fmt.Println(err)
  18. return
  19. }
  20. var proxyConn *net.TCPConn
  21. if data[0] == 0x03 { // RTMP first byte.
  22. proxyConn = createLocalConnection(RTMPPort)
  23. } else {
  24. proxyConn = createLocalConnection(HTTPPort)
  25. }
  26. proxyConn.Write(data[:n])
  27. defer proxyConn.Close()
  28. // Request loop
  29. go func() {
  30. for {
  31. data := make([]byte, 1024*1024)
  32. n, err := conn.Read(data)
  33. if err != nil {
  34. break
  35. }
  36. proxyConn.Write(data[:n])
  37. }
  38. }()
  39. // Response loop
  40. for {
  41. data := make([]byte, 1024*1024)
  42. n, err := proxyConn.Read(data)
  43. if err != nil {
  44. break
  45. }
  46. conn.Write(data[:n])
  47. }
  48. }
  49. func main() {
  50. listener, err := net.ListenTCP("tcp", addr)
  51. if err != nil {
  52. panic(err)
  53. }
  54. for {
  55. conn, err := listener.AcceptTCP()
  56. if err != nil {
  57. fmt.Println(err)
  58. continue
  59. }
  60. go server.ProxyConnection(conn)
  61. }
  62. }

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:

确定