首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
宝塔
V2EX  ›  程序员

websocket 方案求助 -- 如何实现实时进度提交给前端

  •  
  •   chaleaochexist · 50 天前 · 2809 次点击
    这是一个创建于 50 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前端点一个按钮, 发送一个 ajax, 后端开始做动作,同时不停的将处理进度实时推送给前端.

    现在的思路是, 前端和后端 ajax 同时绑定同一个 group. 后端给 group 发消息, websocket 接什么消息发什么消息,向同一个 group. 这样前端就收到消息了.

    def view(request):
        ws = websocket(***)
        # do something business logic
        ws.send()
        return 666
    

    伪代码大概是这样的,但是 websocket server 端的心跳机制会导致和 view 里面创建的 ws 客户端失去连接.

    现在的解决方案是, 在 view 里面创建一个线程, 在新起的线程里面 不停的发消息给 websocket server.

    拍脑袋感觉,应该在 view 里面做一个非阻塞带回调的 websocket 客户端,但是...如何实现呢...

    第 1 条附言  ·  49 天前

    实际效果 逻辑框图

    30 回复  |  直到 2019-09-27 13:06:53 +08:00
        1
    halk   50 天前
    1. websocket server 端的心跳机制会导致和 view 里面创建的 ws 客户端失去连接.
    --这句话怎么理解?

    2. 试试 SSE,能满足你的需求吗
        2
    wolfie   50 天前
    ws 不是长连接吗,为什么会断开。

    客户端定时检查连接是否可用,断了就重连。
        3
    Carseason   50 天前
    websocket 是长连接,你心跳也不需要把当前的断开重连吧?
    服务端应该把客户端存到一个队列里面,然后当服务端接收到新消息后对该队列推送消息来实现广播
        4
    hantsy   50 天前
    SSE 比较适合
        5
    kxiaong   50 天前
    拍脑袋想, 你这样子连 websocket 链接也创建不起来吧?

    并不是你在 server 端起一个 websocket server,然后不停的 send,客户端就会接收数据。 在 websocket 链接创建之前还有 http 报文做协商认证和链接过程。

    websocket 的第一个报文是这样的 (ietf rfc 7977):
    ```
    GET / HTTP/1.1
    Host: a.example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Origin: http://www.example.com
    Sec-WebSocket-Protocol: msrp
    Sec-WebSocket-Version: 13
    ```

    一个可能的办法是: 页面先跟 server 创建一个 websocket 链接,使用 groupId 标识这个链接。

    页面点击动作的 ajax 将自己的 groupId 作为参数传入 view。view 触发业务逻辑以后就返回 ok, 不需要阻塞等待。

    业务逻辑处理过程中的进度信息,通过 websocket 推送到 client
        6
    neoblackcap   50 天前 via iPhone
    websocket 之类的长连接就该用 Tornado 之类的框架,一般基于 request-response 的框架当然会断
        7
    KuroNekoFan   50 天前 via iPhone
    你这提问看得我一头雾水
        8
    21paradox   50 天前
    用 server send events 吧,sse 或者前端轮询
        9
    mengqi   50 天前
    看了几遍题主的说明,最后终于确认:没看懂…
    1. 为什么前后端不能直接建立 websocket 长连接,而需要一个 group ?
    2. “server 端的心跳机制”是指服务器向客户端发送心跳还是客户端向服务端发送心跳?又为什么会导致客户端断开连接?
    3. 你贴的伪代码是服务端的代码吗?为什么后面的解决方案又说“在 view 里面创建一个线程, ……不停的发消息给 websocket server”?
        10
    zhuzhibin   50 天前 via iPhone
    连接成功做你需要做的事 如果断了自己做一次重连
        11
    izoabr   49 天前
    我是直接用 rabbitmq 的 websocket,然后后台和前台都连一下,前台监控队列做回调显示进度就好了。
        12
    chaleaochexist   49 天前
    @mengqi 我当时问这个问题的时候就想到了可能看不懂...

    一会儿主贴补一个框图...供您参考.
    1. 为什么前后端不能直接建立 websocket 长连接,而需要一个 group ?
    前端 后端 wsserver 我们现在有这三个实例, 后端需要将消息发送给前端 通过 ws. name 后端和 ws 之间需要通信,我们通过 ws.
    否则 ws 后端接到的消息如何推送给前端?
    2. “server 端的心跳机制”是指服务器向客户端发送心跳还是客户端向服务端发送心跳?又为什么会导致客户端断开连接?
    这个是 server 向 client 发送心跳, 断开连接是服务端(daphne)的配置,心跳间隔 20s.超过 20s 就主动断开连接. 修改心跳间隔是解决思路之一,但是目前我们并不想采用.
    3. 你贴的伪代码是服务端的代码吗?为什么后面的解决方案又说“在 view 里面创建一个线程, ……不停的发消息给 websocket server”?
    是后端的代码,后端属于 ws 客户端. 前端也是 ws 客户端.
    因为,如果客户端不停的给 ws 服务端,那么服务端就不会,也不需要发送心跳了.
        13
    chaleaochexist   49 天前
    @neoblackcap 可不可以把一个 ws client 做成 异步形式?
    现在的项目就是用 django 做的,不可能为了一个 api 换框架啊.代价大了点.
        14
    chaleaochexist   49 天前
    @wolfie
    客户端定时检查是指前端定时检查吗? 前端没有问题,浏览器会替我们发送心跳包.
    我们现在遇到的问题是另一个客户端 -- http 后端. 定时检查如何处理?我们现在是起了一个线程.
    @Carseason
    这个是框架的做法.我也没好办法.
    @kxiaong
    我就是这么做的. 但是遇到了 ws 服务端 20 秒会发送心跳包给 http 服务端. 我现在需要在 http 服务端 view 里面做一个非阻塞最好是异步的 ws 客户端. 除了起新线程, 有没有更好的办法.譬如用 gevent 有没有例子.
        15
    neoblackcap   49 天前 via iPhone
    @chaleaochexist 那你去用 Django 官方出的 channel 啊
        16
    Nasei   49 天前 via Android
    这么麻烦的吗…进度更新只用过 netcore 的 signalR,基本傻瓜式操作
        17
    zazalu   49 天前
    没看懂+1 不过我是因为菜没看懂 mark 下
        18
    longkas   49 天前 via Android
        19
    b821025551b   49 天前   ♥ 1
    这个是 server 向 client 发送心跳, 断开连接是服务端(daphne)的配置,心跳间隔 20s.超过 20s 就主动断开连接. 修改心跳间隔是解决思路之一,但是目前我们并不想采用.
    -----------------------------------------------

    怎么总觉得怪怪的?正常心跳 1s 一个,20s 是没收到心跳就断了;你这是设置了 40s 一个心跳然后 20s 没心跳就断了?
    不想修改心跳是什么鬼?
    还有,即使是断了,再请求一个重连不就行了?想那么麻烦干吗?
        20
    chaleaochexist   49 天前
    @b821025551b 谢谢,最后一句话有用.我没想到.

    心跳就是 20s 间隔.我看代码默认是这个配置.超过 20S(这个是心跳间隔)+30S(这个是 timeout) 就会主动断开连接.
    忘记是 channel 还是 daphne 的代码了.\
    ```
    class Server():
    def __init__():
    pass # 就在这里
    ```

    @neoblackcap 谢谢我用的就是 channel,另外本问题和 ws server 端没有太大关系,我的问题是如何做一个异步非阻塞的 ws 客户端.channel 还支持客户端吗?像 aiohttp 那样?
        21
    tanszhe   49 天前
    这么简单的问题 ,搞不清楚 ……
        22
    MonoLogueChi   49 天前 via Android
    @Nasei signalR 吹?我也喜欢用
        23
    LeeSeoung   49 天前
    ws 不是双向的么。。没搞明白你想做啥。。为啥 ws 会自己断。。
        24
    chaleaochexist   49 天前
    @LeeSeoung 和本题无关的一种可能, timeout 不就断了吗?很好理解.
        25
    shuizhengqi   49 天前
    直接 setInterval 不好使么?
        26
    shuizhengqi   49 天前
    1s 一次,就能做到跟实时差不多的效果
        27
    zpf   49 天前
    前端不应该直接请求 websocket 服务器,为什么还要先请求 view 层,view 层在做请求转发?
        28
    chaleaochexist   49 天前
    @shuizhengqi 当然可以 setInterval 直接发 ajax 就可以了,和 websocket 有啥关系?

    @zpf 实时推送后台的处理进度.
    view 在做一个业务逻辑,并将业务逻辑的进度发送给前端.
    你的意思是说,这个业务逻辑不用 ajax 而是用 websocket 来实现是吗?
        29
    hsfzxjy   49 天前 via Android
    django channels,了解一下
        30
    chaleaochexist   49 天前
    @hsfzxjy 谢谢我用的就是 channel,另外本问题和 ws server 端没有太大关系,我的问题是如何做一个异步非阻塞的 ws 客户端.channel 还支持客户端吗?像 aiohttp 那样?
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2330 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 23ms · UTC 14:54 · PVG 22:54 · LAX 06:54 · JFK 09:54
    ♥ Do have faith in what you're doing.