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

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

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

    我的服务器通过 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  
       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   ·   我们的愿景   ·   实用小工具   ·   1385 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 79ms · UTC 23:43 · PVG 07:43 · LAX 16:43 · JFK 19:43
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.