服务器怎么通过 websocket 主动向前端推送数据?向各位大佬请教 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
Rieouu
V2EX    程序员

服务器怎么通过 websocket 主动向前端推送数据?向各位大佬请教

  •  
  •   Rieouu 2018-07-23 09:44:41 +08:00 15819 次点击
    这是一个创建于 2642 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我的服务器通过 socket 接收到数据,请问怎么通过 websocket 实现后台有数据就推送到前台呢?看了 websocket 的例子,通过 onMessage 方法都是需要前台有消息请求才会触发这个方法,有没有主动的 write 方法直接写到前台呢,希望有做过这方面问题的大佬赐教

    63 条回复    2019-03-20 18:58:01 +08:00
    Rieouu
        1
    Rieouu  
    OP
       2018-07-23 09:45:07 +08:00
    要是有现成的轮子就更好了
    satgi
        2
    satgi  
       2018-07-23 09:53:38 +08:00
    任何时候,只要获取到已经连接了的客户端就可以。
    ben1024
        3
    ben1024  
       2018-07-23 09:54:56 +08:00
    Rieouu
        4
    Rieouu  
    OP
       2018-07-23 09:55:31 +08:00
    @satgi 请问具体怎么做呢,我对 websocket 不怎么熟所以很迷惑,谢谢
    Rieouu
        5
    Rieouu  
    OP
       2018-07-23 09:57:33 +08:00
    @ben1024 您这个的确符合我的要求,不过要是 Java 的就更好了,看来使用 websocket 肯定是可以实现的,谢谢
    qiushijie
        6
    qiushijie  
       2018-07-23 10:00:16 +08:00 via Android
    用一个 map 把客户端链接保存,然后遍历去发送就行了
    Rieouu
        7
    Rieouu  
    OP
       2018-07-23 10:02:55 +08:00
    @qiushijie 您说的这个发送是指调用某个方法吗,我就是在这里不明白怎么发送消息
    liuxu
        8
    liuxu  
       2018-07-23 10:03:11 +08:00
    onMessage 更像一个路由,所有人连到 onMessage,让它来处理
    lsls931011
        9
    lsls931011  
       2018-07-23 10:05:23 +08:00
    opengps
        10
    opengps  
       2018-07-23 10:05:51 +08:00
    连接之后,谁都可以互相发送,你需要的是每个 websocket 有个 id 标识,长连接建立后,通过 id 识别,直接推送,前端就会收到
    satgi
        11
    satgi  
       2018-07-23 10:05:56 +08:00
    ```
    let clients = [];

    wss.on('connection', ws => {
    clients.push(ws);
    // onMessage
    ws.on('message', message => {
    pushMessage('message received');
    });
    });

    function pushMessage (message) {
    clients.forEach(client =>{
    client.send(message);
    });
    }

    // data received from socket, then push to clients
    let data = dataFromSocket;
    pushMessage(data);
    ```
    windfarer
        12
    windfarer  
       2018-07-23 10:05:59 +08:00
    neoblackcap
        13
    neoblackcap  
       2018-07-23 10:06:55 +08:00
    1.到底是 webscoket 还是 socket 这个要分清
    2.如 6L @qiushijie 所说,你先记录好每个连接到底是谁,然后分别对每个连接写你要推送的消息就好了
    mokeyjay
        14
    mokeyjay  
       2018-07-23 10:07:27 +08:00
    用你的语言+空格+websocket 作为关键词组搜一下不就知道了
    Rieouu
        15
    Rieouu  
    OP
       2018-07-23 10:10:51 +08:00
    @neoblackcap sorry 没说清楚哈,我要发送的消息是服务器通过 socket 接收的,是一个 TCP 消息,接收到消息后要把它显示到前端,所以用 websocket,看了各位大佬的回复,我还是先把 websocket 弄清楚,谢谢您
    aurelia
        16
    aurelia  
       2018-07-23 10:11:26 +08:00
    多监听一个 tcp 或者 http 端口 后台有新数据 就请求 轮询 fd 或者直接在后台发送 ws 发送完就断掉也是可以的
    neoblackcap
        17
    neoblackcap  
       2018-07-23 10:12:55 +08:00
    @Rieouu 你这样显然要求建立两组连接吧,一组 websocket,一组 socket,socket 收到数据,然后通过队列之类的方式,批量往 websocket 写入消息
    Rieouu
        18
    Rieouu  
    OP
       2018-07-23 10:17:33 +08:00
    @neoblackcap 目前使用的是 netty 接收消息,本来想的是 netty 收到消息直接通过 websocket 推送,然后坐了半天没做出来,实验室项目老师催得紧所以在 v 站向大佬提问。。用消息队列会不会太麻烦了,毕竟以前没弄过
    Rieouu
        19
    Rieouu  
    OP
       2018-07-23 10:19:17 +08:00
    @mokeyjay 搜到一大堆聊天室都不是我想要的,所以来 v 站寻求大佬帮助
    qinxi
        20
    qinxi  
       2018-07-23 10:21:06 +08:00
    你消息怎么来的在这个场景中不重要.重要的是你现在需要往网页上推送,那就使用 websocket ,最基本的 百度都能搜出来.
    crist
        21
    crist  
       2018-07-23 10:21:19 +08:00
    workerman 是可以的,swoole 就不知道了。
    satgi
        22
    satgi  
       2018-07-23 10:22:19 +08:00
    @Rieouu
    看#11 代码,我把向客户端发消息的代码封装在 pushMessage 方法里,你什么时候想向客户端发消息,调用 pushMessage 就可以了。

    这里的关键是 clients 变量,用来存储已经连接的客户端,只要你想发消息时候可以访问到 clients,就可以向里面的任意客户端发消息。
    qinxi
        23
    qinxi  
       2018-07-23 10:22:27 +08:00
    @Rieouu 能筛选出自己需要的东西应该是程序员最基本的技能吧.你说你想要轮胎,别人给你一辆汽车.你说不行,我只要轮胎
    xiaopenggggggg
        24
    xiaopenggggggg  
       2018-07-23 10:22:50 +08:00
    前端是是要订阅 websocket 推送的节点的
    myyou
        25
    myyou  
       2018-07-23 10:27:46 +08:00
    使用消息队列,每一个连接就启动一个线程,这个线程记录连接对象和订阅一个消息频道(消息频道名字写入缓存),持续监听这个消息频道,有消息就推送,服务端只需要向这个消息频道推送消息就行。
    Rieouu
        26
    Rieouu  
    OP
       2018-07-23 10:30:57 +08:00
    @qinxi 说的对,可能是自己不懂的东西就倾向于寻求帮助,bad coder
    Rieouu
        27
    Rieouu  
    OP
       2018-07-23 10:31:51 +08:00
    @myyou 你这个比较靠谱,我正在这方面努力
    Rieouu
        28
    Rieouu  
    OP
       2018-07-23 10:33:10 +08:00
    @satgi 谢谢哈,我正在研究大佬的代码呢
    cnit
        29
    cnit  
       2018-07-23 10:50:15 +08:00
    Rieouu
        30
    Rieouu  
    OP
       2018-07-23 10:54:38 +08:00
    @cnit 这个不错哦,谢谢
    wm5d8b
        31
    wm5d8b  
       2018-07-23 12:42:02 +08:00 via Android
    spring boot 官方不是有现成的例子嘛
    jswh
        32
    jswh  
       2018-07-23 12:50:54 +08:00
    socket io 了解一下
    sarices
        33
    sarices  
       2018-07-23 13:48:23 +08:00
    swoole 我是把服务器当成一个特别客户端,用客户端方式向服务器发送需要推送的消息,然后通过 onMessage 推送到其他客户端
    Rieouu
        34
    Rieouu  
    OP
       2018-07-23 13:57:17 +08:00
    @sarices 还可以这么做吗,服务器用作客户端,我来了解一下
    qiayue
        35
    qiayue  
    PRO
       2018-07-23 14:00:29 +08:00   1
    可以采用订阅机制
    假设你有温度和湿度两个数据,有 A、B 两个页面,A 只需要实时显示温度数据,B 需要实时显示温度和湿度两个数据
    浏览器打开 AB 页面后,主动连接到你的 websocket 服务,然后发送需要订阅的数据
    websocket 服务有一个 map 记录连接,以及对应的连接订阅了哪些数据
    你 netty 收到数据后,通过某种方式传给 websocket 服务(可以通过 http 传,也可以 socket 传,或者其他方式)
    websocket 服务每次收到 netty 传过来的一个数据,就从 map 中找出订阅了这个数据的所有连接,循环发送
    页面收到收据后,显示出来
    Rieouu
        36
    Rieouu  
    OP
       2018-07-23 14:02:56 +08:00
    @wm5d8b 看来要学习一下 springboot 了
    Rieouu
        37
    Rieouu  
    OP
       2018-07-23 14:06:30 +08:00
    @qiayue 有大佬建议把 netty 收到的消息放到消息队列,websocket 从消息队列读消息发布出去,跟你说的还是挺像的,我正在看着方面,谢谢你的回复~
    e8c47a0d
        38
    e8c47a0d  
       2018-07-23 14:10:30 +08:00
    socket.io 把,相当于是一个 WebSocket 的包装,相对自己写会方便很多,碰到不支持 websocket 的浏览器,socket.io 还能用长链接、pooling 模式。
    Rieouu
        39
    Rieouu  
    OP
       2018-07-23 14:20:21 +08:00
    @e8c47a0d 好的,都在看一下
    zrlhk
        40
    zrlhk  
       2018-07-23 14:43:33 +08:00
    workerman swoole 轮子多了去了
    Rieouu
        41
    Rieouu  
    OP
       2018-07-23 15:05:07 +08:00
    @zrlhk 主要我后台使用 Java 做的,Java 要是有类似 workman 的框架就好了
    zchlwj
        42
    zchlwj  
       2018-07-23 15:06:34 +08:00
    @Rieouu spring-boot websocket 现成的轮子
    inoki
        43
    inoki  
       2018-07-23 15:07:44 +08:00 via Android
    @crist swoole 有个 server 主动 push 的方法可以实现
    Rieouu
        44
    Rieouu  
    OP
       2018-07-23 15:19:30 +08:00
    @zchlwj 可以主动 push 吗,我读书少别骗我哈
    pipixia
        45
    pipixia  
       2018-07-23 16:49:29 +08:00 via Android
    记得 tomcat 有现成的 websocket 直接在 onMessage 里面遍历 session 发过去就行了
    Rieouu
        46
    Rieouu  
    OP
       2018-07-23 17:11:57 +08:00
    @pipixia onmessage 是需要前端发消息来触发这个方法,可是我的数据来自于服务器,不能直接调用 onmessage 发送吧
    tilv37
        47
    tilv37  
       2018-07-23 18:05:04 +08:00
    应该可以在服务端维护一个客户端的 map 啊,然后取出制定客户端的连接推消息就行了
    mary9
        48
    mary9  
       2018-07-23 19:25:04 +08:00   1
    用过 socket.io ,也研究过这个问题。socket.io 主动发送的话,有两个,一个是一开始客户端连接到服务器,然后有一个监听连接的事件,在这个连接事件中写你要的发送给客户端的东西。后面的话,只能是通过一个定时器了,我之前写的是 setInterval,定时向客户端发送需要的数据。不过这个方法需要在断开连接的时候清除掉你生成的 setInterval,不然 CPU 的内存会上升的。后面也没想到其他的方法,我再研究一下来补坑。
    limbo0
        49
    limbo0  
       2018-07-23 19:35:08 +08:00
    单端推送可以看看 sse
    xm0625
        50
    xm0625  
       2018-07-23 19:57:28 +08:00
    可以去看下我 BusHelper 项目 中间用到了 WebSocket 技术
    Rieouu
        51
    Rieouu  
    OP
       2018-07-23 20:18:22 +08:00
    @mary9 期待您研究的救国哦
    Rieouu
        52
    Rieouu  
    OP
       2018-07-23 20:19:02 +08:00
    @mary9 期待您研究的结果哈
    Rieouu
        53
    Rieouu  
    OP
       2018-07-23 20:19:40 +08:00
    @xm0625 去看大佬的项目~
    pipixia
        54
    pipixia  
       2018-07-23 22:12:50 +08:00 via Android
    @Rieouu 你总有地方放 session 吧 直接遍历他发送消息
    Rieouu
        55
    Rieouu  
    OP
       2018-07-23 22:39:20 +08:00
    @pipixia session 是放在一个容器对象里面的,我来试试看
    wdlth
        56
    wdlth  
       2018-07-23 23:18:44 +08:00
    把 Session 存起来,找到 Session 就发
    Rieouu
        57
    Rieouu  
    OP
       2018-07-24 08:40:29 +08:00
    @wdlth 大佬说的是对的,我按照这个试验了是可行的
    kba977
        58
    kba977  
       2018-07-24 10:33:12 +08:00
    hosaos
        59
    hosaos  
       2018-07-24 11:01:35 +08:00
    netty socket io 包含了自动重连一些封装好的功能 可以看看
    Rieouu
        60
    Rieouu  
    OP
       2018-07-24 13:13:34 +08:00
    @hosaos 谢谢我看一下哈
    Rieouu
        61
    Rieouu  
    OP
       2018-07-24 13:13:52 +08:00
    @kba977 谢谢
    youngce
        62
    youngce  
       2019-03-20 14:34:07 +08:00
    大佬,你的问题最后是怎么解决的?我的需求和你几乎一样,也是有一个 socket 客户端,接收到消息以后需要利用 websocket 推送到 web 前端,只不过我是 py,可以说一下你最后的解决思路吗
    Rieouu
        63
    Rieouu  
    OP
       2019-03-20 18:58:01 +08:00
    @youngce 我的后台使用的是 springboot+springmvc,接收 socket 请求使用的是 netty,思路就是 netty 收到数据后对数据进行解析并包装成前端需要的 JSON 形式,然后通过 websocket 直接推送给所有的客户端,你只要在 websocket 保存每一个 websocket 连接,然后封装好相应的 push 推送方法,我当时是参考这个做的: https://www.cnblogs.com/xdp-gacl/p/5193279.html
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     957 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 22:33 PVG 06:33 LAX 15:33 JFK 18:33
    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