websocket 方案求助 -- 如何实现实时进度提交给前端 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
chaleaochexist
V2EX    程序员

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

  •  
  •   chaleaochexist 2019-09-26 17:17:29 +08:00 6373 次点击
    这是一个创建于 2227 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前端点一个按钮, 发送一个 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 条附言    2019-09-27 07:11:49 +08:00

    实际效果 逻辑框图

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

    2. 试试 SSE,能满足你的需求吗
    wolfie
        2
    wolfie  
       2019-09-26 19:17:59 +08:00
    ws 不是长连接吗,为什么会断开。

    客户端定时检查连接是否可用,断了就重连。
    Carseason
        3
    Carseason  
       2019-09-26 19:25:53 +08:00
    websocket 是长连接,你心跳也不需要把当前的断开重连吧?
    服务端应该把客户端存到一个队列里面,然后当服务端接收到新消息后对该队列推送消息来实现广播
    hantsy
        4
    hantsy  
       2019-09-26 20:39:54 +08:00
    SSE 比较适合
    kxiaong
        5
    kxiaong  
       2019-09-26 20:57:06 +08:00
    拍脑袋想, 你这样子连 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
    neoblackcap
        6
    neoblackcap  
       2019-09-26 21:01:42 +08:00 via iPhone
    websocket 之类的长连接就该用 Tornado 之类的框架,一般基于 request-response 的框架当然会断
    KuroNekoFan
        7
    KuroNekoFan  
       2019-09-26 21:03:53 +08:00 via iPhone
    你这提问看得我一头雾水
    21paradox
        8
    21paradox  
       2019-09-26 21:17:37 +08:00
    用 server send events 吧,sse 或者前端轮询
    mengqi
        9
    mengqi  
       2019-09-26 21:31:58 +08:00
    看了几遍题主的说明,最后终于确认:没看懂…
    1. 为什么前后端不能直接建立 websocket 长连接,而需要一个 group ?
    2. “server 端的心跳机制”是指服务器向客户端发送心跳还是客户端向服务端发送心跳?又为什么会导致客户端断开连接?
    3. 你贴的伪代码是服务端的代码吗?为什么后面的解决方案又说“在 view 里面创建一个线程, ……不停的发消息给 websocket server”?
    zhuzhibin
        10
    zhuzhibin  
       2019-09-26 22:12:30 +08:00 via iPhone
    连接成功做你需要做的事 如果断了自己做一次重连
    izoabr
        11
    izoabr  
       2019-09-26 23:15:19 +08:00
    我是直接用 rabbitmq 的 websocket,然后后台和前台都连一下,前台监控队列做回调显示进度就好了。
    chaleaochexist
        12
    chaleaochexist  
    OP
       2019-09-27 07:04:56 +08:00
    @mengqi 我当时问这个问题的时候就想到了可能看不懂...

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

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

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

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

    @zpf 实时推送后台的处理进度.
    view 在做一个业务逻辑,并将业务逻辑的进度发送给前端.
    你的意思是说,这个业务逻辑不用 ajax 而是用 websocket 来实现是吗?
    hsfzxjy
        29
    hsfzxjy  
       2019-09-27 12:25:18 +08:00 via Android
    django channels,了解一下
    chaleaochexist
        30
    chaleaochexist  
    OP
       2019-09-27 13:06:53 +08:00
    @hsfzxjy 谢谢我用的就是 channel,另外本问题和 ws server 端没有太大关系,我的问题是如何做一个异步非阻塞的 ws 客户端.channel 还支持客户端吗?像 aiohttp 那样?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2549 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 28ms UTC 13:55 PVG 21:55 LAX 06:55 JFK 09:55
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86