Allenxuxu / gev

🚀Gev is a lightweight, fast non-blocking TCP network library / websocket server based on Reactor mode. Support custom protocols to quickly and easily build high-performance servers.
MIT License
1.73k stars 194 forks source link

websocket http header保存 #33

Closed Allenxuxu closed 4 years ago

Allenxuxu commented 4 years ago

websocket升级的时候需要把http header保存下来的,里面的数据后面conn处理请求要用到的,现在看起来没法做到,需要修改框架支持,

Originally posted by @lyfunny in https://github.com/Allenxuxu/gev/issues/4#issuecomment-613216254

Allenxuxu commented 4 years ago

这是一个特性需求,我把 issue 移到这里。

目前 websocket 插件支持还不够完善。 不过插件和 gev 框架是分开的,修改 websocket 相关部分就好了。 通过 connection 的 Context 保存 header ,似乎改动不大。

func (c *Connection) SetContext(ctx interface{}) {
    c.ctx = ctx
}

https://github.com/Allenxuxu/gev/tree/master/plugins/websocket

ghost commented 4 years ago

这个EventLoop中的onMessage执行是同步的,如果里面有网络调用,会阻塞EventLoop,生成一个gorutine执行的话返回消息有发送不了了,websocket Send没法用

MrChang0 commented 4 years ago

这个EventLoop中的onMessage执行是同步的,如果里面有网络调用,会阻塞EventLoop,生成一个gorutine执行的话返回消息有发送不了了,websocket Send没法用

网络调用为什么会阻塞EventLoop?

ghost commented 4 years ago

这个EventLoop中的onMessage执行是同步的,如果里面有网络调用,会阻塞EventLoop,生成一个gorutine执行的话返回消息有发送不了了,websocket Send没法用

网络调用为什么会阻塞EventLoop?

我的cpu32核心,eventloop是由32个goroutine执行的,当执行到OnMessage的时候,如果发生网络调用,那么这个goroutine就休眠了,那么就没有goroutine执行eventloop了,没法处理到来的请求了.现在我是在OnMessage里面新生成一个goroutine执行业务的,缺点就是返回数据需要用Send调用,OnMessage的返回值没用

Allenxuxu commented 4 years ago

这个EventLoop中的onMessage执行是同步的,如果里面有网络调用,会阻塞EventLoop,生成一个gorutine执行的话返回消息有发送不了了,websocket Send没法用

网络调用为什么会阻塞EventLoop?

我的cpu32核心,eventloop是由32个goroutine执行的,当执行到OnMessage的时候,如果发生网络调用,那么这个goroutine就休眠了,那么就没有goroutine执行eventloop了,没法处理到来的请求了.现在我是在OnMessage里面新生成一个goroutine执行业务的,缺点就是返回数据需要用Send调用,OnMessage的返回值没用

不应该在 OnMessage 做耗时的操作,如果比较耗时,最好只在 OnMessage 里切割数据,然后使用 Send 发送。

Allenxuxu commented 4 years ago

@lyfunny 考虑 在 gev 里增加一个协程池, OnMessage 函数放到协程池中执行。

Allenxuxu commented 4 years ago

https://github.com/Allenxuxu/gev/blob/master/example/websocket/main.go

websocke 增加了取 header 的例子 @lyfunny

func main() {
//....

    wsUpgrader := &ws.Upgrader{}
    wsUpgrader.OnHeader = func(c *connection.Connection,key, value []byte) error {
        fmt.Println(string(key),":" ,string(value))

              // 这个回调函数会在 协议升级成功被调用
              // 在这里可以将需要的 header 保存起来,通过 c.SetContext 方法

        return nil
    }

    s, err := NewWebSocketServer(handler, wsUpgrader,
        gev.Network("tcp"),
        gev.Address(":"+strconv.Itoa(port)),
        gev.NumLoops(loops))
    if err != nil {
        panic(err)
    }

    s.Start()
}
yiippee commented 4 years ago

https://github.com/Allenxuxu/gev/blob/master/example/websocket/main.go

websocke 增加了取 header 的例子 @lyfunny

func main() {
//....

  wsUpgrader := &ws.Upgrader{}
  wsUpgrader.OnHeader = func(c *connection.Connection,key, value []byte) error {
      fmt.Println(string(key),":" ,string(value))

              // 这个回调函数会在 协议升级成功被调用
              // 在这里可以将需要的 header 保存起来,通过 c.SetContext 方法

      return nil
  }

  s, err := NewWebSocketServer(handler, wsUpgrader,
      gev.Network("tcp"),
      gev.Address(":"+strconv.Itoa(port)),
      gev.NumLoops(loops))
  if err != nil {
      panic(err)
  }

  s.Start()
}

这样设置好像没用啊,你在这里设置为true了

        out, _, err = p.upgrade.Upgrade(c, buffer)
        if err != nil {
            log.Error("Websocket Upgrade :", err)
            return
        }
        c.SetContext(true)        // 设置为true,标志已经upgrade过了