英文:
golang: serving net.Conn using a gin router
问题
我有一个处理传入TCP连接的函数:
func Handle(conn net.Conn) error {
// ...
}
此外,我有一个已初始化的gin路由器,并实现了处理函数:
router := gin.New()
router.GET(...)
router.POST(...)
router.Run(addr)
调用将在 addr
上启动一个独立的HTTP服务器。
有没有办法在不运行独立的HTTP服务器的情况下,使用这个路由器在 Handle
函数中处理传入的连接?
英文:
I have a function that handles an incoming TCP connection:
func Handle(conn net.Conn) error {
// ...
}
Also, I have an initialized gin router with implemented handles:
router := gin.New()
router.GET(...)
router.POST(...)
The router.Run(addr)
call will start a separate HTTP server on the addr
.
Is there any way to handle incoming connections inside the Handle
function using this router without running a separate HTTP server?
答案1
得分: 4
创建一个接受连接的 net.Listener 实现,通过在通道上接收连接:
type listener struct {
ch chan net.Conn
addr net.Addr
}
// newListener 创建一个通道监听器。addr 参数是监听器的网络地址。
func newListener(addr net.Addr) *listener {
return &listener{
ch: make(chan net.Conn),
addr: addr,
}
}
func (l *listener) Accept() (net.Conn, error) {
c, ok := <-l.ch
if !ok {
return nil, errors.New("closed")
}
return c, nil
}
func (l *listener) Close() error { return nil }
func (l *listener) Addr() net.Addr { return l.addr }
通过将连接发送到通道来处理连接:
func (l *listener) Handle(c net.Conn) error {
l.ch <- c
return nil
}
下面是如何将它们整合在一起的方法:
- 创建监听器:
s := newListener(someAddr)
- 像往常一样配置 Gin 引擎。
router := gin.New()
router.GET(...)
router.POST(...)
- 使用通道监听器和 Gin 引擎在一个 goroutine 中运行 net/http 服务器:
err := http.Serve(s, router)
if err != nil {
// 处理错误
}
- 在调度代码中,调用
s.Handle(c)
将连接传递给 net/http 服务器,然后传递给 Gin 引擎。
英文:
Create a net.Listener implementation that accepts connections by receiving on a channel:
type listener struct {
ch chan net.Conn
addr net.Addr
}
// newListener creates a channel listener. The addr argument
// is the listener's network address.
func newListener(addr net.Addr) *listener {
return &listener{
ch: make(chan net.Conn),
addr: addr,
}
}
func (l *listener) Accept() (net.Conn, error) {
c, ok := <-l.ch
if !ok {
return nil, errors.New("closed")
}
return c, nil
}
func (l *listener) Close() error { return nil }
func (l *listener) Addr() net.Addr { return l.addr }
Handle connections by sending to the channel:
func (l *listener) Handle(c net.Conn) error {
l.ch <- c
return nil
}
Here's how to tie it all together:
-
Create the listener:
s := newListener(someAddr)
-
Configure the Gin engine as usual.
router := gin.New() router.GET(...) router.POST(...)
-
Run the net/http server in a goroutine using the channel listener and the Gin engine:
err := http.Serve(s, router) if err != nil { // handle error }
-
In your dispatching code, call the
s.Handle(c)
to pass the connection to the net/http server and then on to the Gin engine.
答案2
得分: 0
对于那些需要使用单个路由器处理来自多个端口的TCP连接的人,我最终找到了一个解决方法。不是在一个端口上运行HTTP服务器,而是使用UNIX套接字运行它,使用router.RunUnix(socketName)
。完整的解决方案包括三个步骤:
-
运行一个HTTP服务器,通过UNIX套接字监听,使用
router.RunUnix(socketName)
。 -
在
Handle
函数内,读取连接中传入的字节,并将它们发送到套接字。之后,从套接字读取HTTP响应,并将其写入连接。 -
关闭连接。
英文:
For those who have a similar task - handle TCP connections from multiple ports using a single router, here's a workaround that I eventually found. Instead of running an HTTP server on a port, I run it with a UNIX socket using router.RunUnix(socketName)
. The full solution consists of three steps:
-
Run a HTTP server to listen through a UNIX socket using
router.RunUnix(socketName)
-
Inside the
Handle
function read the incoming bytes from the connection and send them to the socket. After that, read the HTTP response from the socket and write it into the connection. -
Close the connection.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论