Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >WebSocket实现Web端即时通信

WebSocket实现Web端即时通信

作者头像
用户5224393
发布于 2019-11-19 06:27:29
发布于 2019-11-19 06:27:29
2.5K00
代码可运行
举报
文章被收录于专栏:Java研发军团Java研发军团
运行总次数:0
代码可运行

前言

WebSocket 是HTML5开始提供的一种在浏览器和服务器间进行全双工通信的协议。目前很多没有使用WebSocket进行客户端服务端实时通信的web应用,大多使用设置规则时间的轮询,或者使用长轮询较多来处理消息的实时推送。这样势必会较大程度浪费服务器和带宽资源,而我们现在要讲的WebSocket正是来解决该问题而出现,使得B/S架构的应用拥有C/S架构一样的实时通信能力。

HTTP和WebSocket比较

HTTP

HTTP协议是半双工协议,也就是说在同一时间点只能处理一个方向的数据传输,同时HTTP消息也是过于庞大,里面包含大量消息头数据,真正在消息处理中很多数据不是必须的,这也是对资源的浪费。

  • 定时轮询:定时轮询就是客户端定时去向服务器发送HTTP请求,看是否有数据,服务器接受到请求后,返回数据给客户端,本次连接也会随着关闭。该实现方案最简单,但是会存在消息延迟和大量浪费服务器和带宽资源。
  • 长轮询:长轮询与定时轮询一样,也是通过HTTP请求实现,但这里不是定时发送请求。客户端发送请求给服务端,这时服务端会hold住该请求,当有数据过来或者超时时返回给请求的客户端并开始下一轮的请求。

WebSocket

WebSocket在客户端和服务端只需一次请求,就会在客户端和服务端建立一条通信通道,可以实时相互传输数据,并且不会像HTTP那样携带大量请求头等信息。因为WebSocket是基于TCP双向全双工通信的协议,所以支持在同一时间点处理发送和接收消息,做到实时的消息处理。

  • 建立WebSocket连接:建立WebSocket连接,首先客户端先要向服务端发送一个特殊的HTTP请求,使用的协议不是httphttps,而是使用过 wswss(一个非安全的,一个安全的,类似前两者之间的差别),请求头里面要附加一个申请协议升级的信息 Upgrade:websocket,还有随机生成一个 Sec-WebSocket-Key的值,及版本信息 Sec-WebSocket-Version等等。服务端收到客户端的请求后,会解析该请求的信息,包括请求协议升级,版本校验,以及将 Sec-WebSocket-Key的加密后以 sec-websocket-accept的值返回给客户端,这样客户端和服务端的连接就建立了。
  • 关闭WebSocket连接:客户端和服务端都可发送一个close控制帧,另一端主动关闭连接。

HTTP轮询和WebSocket生命周期示意图

服务端

这里服务端利用Netty的WebSocket开发。这里首先实现服务端启动类,然后自定义处理器来处理WebSocket的消息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.ytao.websocket;
import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.*;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;import io.netty.handler.codec.http.HttpObjectAggregator;import io.netty.handler.codec.http.HttpServerCodec;import io.netty.handler.logging.LogLevel;import io.netty.handler.logging.LoggingHandler;import io.netty.handler.stream.ChunkedWriteHandler;
/** * Created by YANGTAO on 2019/11/17 0017. */public class WebSocketServer {
    public static String HOST = "127.0.0.1";    public static int PORT = 8806;
    public static void startUp() throws Exception {        // 监听端口的线程组        EventLoopGroup bossGroup = new NioEventLoopGroup();        // 处理每一条连接的数据读写的线程组        EventLoopGroup workerGroup = new NioEventLoopGroup();        // 启动的引导类        ServerBootstrap serverBootstrap = new ServerBootstrap();        try {            serverBootstrap.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        protected void initChannel(SocketChannel ch) throws Exception{                            ChannelPipeline pipeline = ch.pipeline();                            pipeline.addLast("logger", new LoggingHandler(LogLevel.INFO));                            // 将请求和返回消息编码或解码成http                            pipeline.addLast("http-codec", new HttpServerCodec());                            // 使http的多个部分组合成一条完整的http                            pipeline.addLast("aggregator", new HttpObjectAggregator(65536));                            // 向客户端发送h5文件,主要是来支持websocket通信                            pipeline.addLast("http-chunked", new ChunkedWriteHandler());                            // 服务端自定义处理器                            pipeline.addLast("handler", new WebSocketServerHandler());                        }                    })                    // 开启心跳机制                    .childOption(ChannelOption.SO_KEEPALIVE, true)                    .handler(new ChannelInitializer<NioServerSocketChannel>() {                        protected void initChannel(NioServerSocketChannel ch) {                            System.out.println("WebSocket服务端启动中...");                        }                    });
            Channel ch = serverBootstrap.bind(HOST, PORT).sync().channel();            System.out.println("WebSocket host: "+ch.localAddress().toString().replace("/",""));            ch.closeFuture().sync();        }catch (Exception e){            e.printStackTrace();        }finally {            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }
    }
    public static void main(String[] args) throws Exception {        startUp();    }}

上面启动类和HTTP协议的类似,所以较好理解。启动类启动后,我们需要处理WebSocket请求,这里自定义 WebSocketServerHandler。我们在处理中设计的业务逻辑有,如果只有一个连接来发送信息聊天,那么我们就以服务器自动回复,如果存在一个以上,我们就将信息发送给其他人。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.ytao.websocket;
import io.netty.channel.Channel;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelPromise;import io.netty.channel.SimpleChannelInboundHandler;import io.netty.handler.codec.http.FullHttpRequest;import io.netty.handler.codec.http.websocketx.*;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.Date;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;
/** * Created by YANGTAO on 2019/11/17 0017. */public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
    private WebSocketServerHandshaker handshaker;
    private static Map<String, ChannelHandlerContext> channelHandlerContextConcurrentHashMap = new ConcurrentHashMap<>();
    private static final Map<String, String> replyMap = new ConcurrentHashMap<>();    static {        replyMap.put("博客", "https://ytao.top");        replyMap.put("公众号", "ytao公众号");        replyMap.put("在吗", "在");        replyMap.put("吃饭了吗", "吃了");        replyMap.put("你好", "你好");        replyMap.put("谁", "ytao");        replyMap.put("几点", "现在本地时间:"+LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));    }
    @Override    public void messageReceived(ChannelHandlerContext channelHandlerContext, Object msg) throws Exception{        channelHandlerContextConcurrentHashMap.put(channelHandlerContext.channel().toString(), channelHandlerContext);        // http        if (msg instanceof FullHttpRequest){            handleHttpRequest(channelHandlerContext, (FullHttpRequest) msg);        }else if (msg instanceof WebSocketFrame){ // WebSocket            handleWebSocketFrame(channelHandlerContext, (WebSocketFrame) msg);        }    }
    @Override    public void channelReadComplete(ChannelHandlerContext channelHandlerContext) throws Exception{        if (channelHandlerContextConcurrentHashMap.size() > 1){            for (String key : channelHandlerContextConcurrentHashMap.keySet()) {                ChannelHandlerContext current = channelHandlerContextConcurrentHashMap.get(key);                if (channelHandlerContext == current)                    continue;                current.flush();            }        }else {            // 单条处理            channelHandlerContext.flush();        }    }
    private void handleHttpRequest(ChannelHandlerContext channelHandlerContext, FullHttpRequest request) throws Exception{        // 验证解码是否异常        if (!"websocket".equals(request.headers().get("Upgrade")) || request.decoderResult().isFailure()){            // todo send response bad            System.err.println("解析http信息异常");            return;        }
        // 创建握手工厂类        WebSocketServerHandshakerFactory factory = new WebSocketServerHandshakerFactory(          "ws:/".concat(channelHandlerContext.channel().localAddress().toString()),                null,                false        );        handshaker = factory.newHandshaker(request);
        if (handshaker == null)            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(channelHandlerContext.channel());        else            // 响应握手消息给客户端            handshaker.handshake(channelHandlerContext.channel(), request);
    }
    private void handleWebSocketFrame(ChannelHandlerContext channelHandlerContext, WebSocketFrame webSocketFrame){        // 关闭链路        if (webSocketFrame instanceof CloseWebSocketFrame){            handshaker.close(channelHandlerContext.channel(), (CloseWebSocketFrame) webSocketFrame.retain());            return;        }
        // Ping消息        if (webSocketFrame instanceof PingWebSocketFrame){            channelHandlerContext.channel().write(              new PongWebSocketFrame(webSocketFrame.content().retain())            );            return;        }
        // Pong消息        if (webSocketFrame instanceof PongWebSocketFrame){            // todo Pong消息处理        }
        // 二进制消息        if (webSocketFrame instanceof BinaryWebSocketFrame){            // todo 二进制消息处理        }
        // 拆分数据        if (webSocketFrame instanceof ContinuationWebSocketFrame){            // todo 数据被拆分为多个websocketframe处理        }
        // 文本信息处理        if (webSocketFrame instanceof TextWebSocketFrame){            // 推送过来的消息            String  msg = ((TextWebSocketFrame) webSocketFrame).text();            System.out.println(String.format("%s 收到消息 : %s", new Date(), msg));
            String responseMsg = "";            if (channelHandlerContextConcurrentHashMap.size() > 1){                responseMsg = msg;                for (String key : channelHandlerContextConcurrentHashMap.keySet()) {                    ChannelHandlerContext current = channelHandlerContextConcurrentHashMap.get(key);                    if (channelHandlerContext == current)                        continue;                    Channel channel = current.channel();                    channel.write(                            new TextWebSocketFrame(responseMsg)                    );                }            }else {                // 自动回复                responseMsg = this.answer(msg);                if(responseMsg == null)                    responseMsg = "暂时无法回答你的问题 ->_->";                System.out.println("回复消息:"+responseMsg);                Channel channel = channelHandlerContext.channel();                channel.write(                        new TextWebSocketFrame("【服务端】" + responseMsg)                );            }        }
    }
    private String answer(String msg){        for (String key : replyMap.keySet()) {            if (msg.contains(key))                return replyMap.get(key);        }        return null;    }
    @Override    public void exceptionCaught(ChannelHandlerContext channelHandlerContext, Throwable throwable){        throwable.printStackTrace();        channelHandlerContext.close();    }
    @Override    public void close(ChannelHandlerContext channelHandlerContext, ChannelPromise promise) throws Exception {        channelHandlerContextConcurrentHashMap.remove(channelHandlerContext.channel().toString());        channelHandlerContext.close(promise);    }
}

刚建立连接时,第一次握手有HTTP协议处理,所以 WebSocketServerHandler#messageReceived会判断是HTTP还是WebSocket,如果是HTTP时,交由 WebSocketServerHandler#handleHttpRequest处理,里面会去验证请求,并且处理握手后将消息返回给客户端。如果不是HTTP协议,而是WebSocket协议时,处理交给 WebSocketServerHandler#handleWebSocketFrame处理,进入WebSocket处理后,这里面有判断消息属于哪种类型,里面包括 CloseWebSocketFramePingWebSocketFramePongWebSocketFrameBinaryWebSocketFrameContinuationWebSocketFrameTextWebSocketFrame,他们都是 WebSocketFrame的子类,并且 WebSocketFrame又继承自 DefaultByteBufHolder

channelHandlerContextConcurrentHashMap是缓存WebSocket已连接的信息,因为我们实现的需求要记录连接数量,当有连接关闭时我们要删除以缓存的连接,所以在 WebSocketServerHandler#close中要移除缓存。

最后的发送文本到客户端,根据连接数量判断。如果连接数量不大于1,那么,我们"价值一个亿的AI核心代码" WebSocketServerHandler#answer来回复客户端消息。否则除了本次接收的连接,消息会发送给其他所有连接的客户端。

客户端

客户端使用JS实现WebSocket的操作,目前主流的浏览器基本都支持WebSocket。支持情况如图:

客户端H5的代码实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1" />    <title>ytao-websocket</title>    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>    <style type="text/css">        #msgContent{            line-height:200%;            width: 500px;            height: 300px;            resize: none;            border-color: #FF9900;        }        .clean{            background-color: white;        }        .send{            border-radius: 10%;            background-color: #2BD56F;        }        @media screen and (max-width: 600px) {            #msgContent{                line-height:200%;                width: 100%;                height: 300px;            }        }    </style></head><script>    var socket;    var URL = "ws://127.0.0.1:8806/ytao";
    connect();
    function connect() {        $("#status").html("<span>连接中.....</span>");        window.WebSocket = !window.WebSocket == true? window.MozWebSocket : window.WebSocket;        if(window.WebSocket){            socket = new WebSocket(URL);            socket.onmessage = function(event){                var msg = event.data + "\n";                addMsgContent(msg);            };
            socket.onopen = function(){                $("#status").html("<span style='background-color: #44b549'>WebSocket已连接</span>");            };
            socket.onclose = function(){                $("#status").html("<span style='background-color: red'>WebSocket已断开连接</span>");                setTimeout("connect()", 3000);            };        }else{            $("#status").html("<span style='background-color: red'>该浏览器不支持WebSocket协议!</span>");        }    }
    function addMsgContent(msg) {        var contet = $("#msgContent").val() + msg;        $("#msgContent").val(contet)    }
    function clean() {        $("#msgContent").val("");    }
    function getUserName() {        var n = $("input[name=userName]").val();        if (n == "")            n = "匿名";        return n;    }
    function send(){        var message = $("input[name=message]").val();        if(!window.WebSocket) return;        if ($.trim(message) == ""){            alert("不能发送空消息!");            return;        }        if(socket.readyState == WebSocket.OPEN){            var msg = "【我】" + message + "\n";            this.addMsgContent(msg);            socket.send("【"+getUserName()+"】"+message);            $("input[name=message]").val("");        }else{            alert("无法建立WebSocket连接!");        }    }
    $(document).keyup(function(){        if(event.keyCode ==13){            send()        }    });</script><body>    <div style="text-align: center;">        <div id="status">            <span>连接中.....</span>        </div>        <div>            <h2>信息面板</h2>            <textarea id="msgContent" readonly="readonly"></textarea>        </div>        <div>            <input class="clean" type="button" value="清除聊天纪录" onclick="clean()" />            <input type="text" name="userName" value="" placeholder="用户名"/>        </div>        <hr>        <div>            <form onsubmit="return false">                <input type="text" name="message" value="" placeholder="请输入消息"/>                <input class="send" type="button" name="msgBtn" value="send" onclick="send()"/>            </form>        </div>        <div>            <br><br>            <img src="http://yangtao.ytao.top/ytao%E5%85%AC%E4%BC%97%E5%8F%B7.jpg">        </div>    </div></body></html>

JS这里实现相对较简单,主要用到:

  • newWebSocket(URL)创建WebSocket对象
  • onopen()打开连接
  • onclose()关闭连接
  • onmessage接收消息
  • send()发送消息

当断开连接后,客户端这边重新发起连接,直到连接成功为止。

启动

客户端和服务端连接后,我们从日志和请求中可以看到上面所提到的验证信息。

客户端:

服务端:

启动服务端后,先实验我们"价值一个亿的AI",只有一个连接用户时,发送信息结果如图:

多个用户连接,这里使用三个连接用户群聊。

用户一:

用户二:

用户三:

到目前为止,WebSocket已帮助我们实现即时通信的需求,相信大家也基本入门了WebSocket的基本使用。

总结

通过本文了解,可以帮助大家入门WebSocket并且解决当前可能存在的一些Web端的通信问题。我曾经在两个项目中也有看到该类解决方案都是通过定时轮询去做的,也或多或少对服务器资源造成一定的浪费。因为WebSocket本身是较复杂的,它提供的API也是比较多,所以在使用过程,要去真正使用好或去优化它,并不是一件很简单的事,也是需要根据现实场景针对性的去做。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-11-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java研发军团 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
WebSocket vs SSE: 实时数据推送到前端的选择与实现(详细)
WebSocket 和 Server-Sent Events (SSE) 都是用于实现实时数据推送的技术,但它们在设计、用途和实现上有一些重要的区别。让我们详细比较这两种技术。
一只牛博
2025/05/31
1000
WebSocket实现Web端即时通信
HTTP协议是半双工协议,也就是说在同一时间点只能处理一个方向的数据传输,同时HTTP消息也是过于庞大,里面包含大量消息头数据,真正在消息处理中很多数据不是必须的,这也是对资源的浪费。
Bug开发工程师
2019/11/27
1.5K0
websocket(三) 进阶!netty框架实现websocket达到高并发
引言: 在前面两篇文章中,我们对原生websocket进行了了解,且用demo来简单的讲解了其用法。但是在实际项目中,那样的用法是不可取的,理由是tomcat对高并发的支持不怎么好,特别是tomcat9之前,可以测试发现websocket连接达到的数量很低,且容易断开。 所以有现在的第三篇,对websocket的一种进阶方法。 什么是Netty Netty是业界最流行的NIO框架之一,它的健壮性、功能、性能、可定制性和可扩展性在同类框架中都是首屈一指的,它已经得到成百上千的商用项目验证,例如Hadoop的R
生活创客
2018/01/30
9.8K0
搭建百万连接服务,使用netty完成websocke的推送
PS:最好是通过代码,自己试一下,了解下百万连接的思路,按照正常是分布式的架构,单机始终是有瓶颈的,100万用户的连接的话单机8g4核轻轻松松,分布式系统就要设计到分布式消息队列,负载均衡,注册中心的概念,推送使用netty方便系统的开发,沾包和拆包的问题方法去解决,而不是自己写一个socket程序很复杂,netty是通过责任链的方式,通过pipline控制之后的步骤。netty的底层是基于NIO,NIO的底层是基于多路复用的机制,多路复用机制是依托于操作系统的,百万连接这个是拼操作系统参数的,java代码是使用的NIO,如果不是使用的NIO,不好意思你达不到,设置到一些系统操作的配置。
IT架构圈
2021/01/04
3.3K0
搭建百万连接服务,使用netty完成websocke的推送
使用Netty框架搭建WebSocket服务器
Netty简单介绍 还记得前面的文章「[ Android即时通讯系列文章(2)网络通信协议选型:应以什么样的标准去选择适合你应用的网络通信协议?](https://links.jianshu.co
大发明家
2021/12/15
2.5K0
Netty之WebSocket协议应用开发
上一篇聊了一下使用Netty进行HTTP协议的应用开发,今儿就来说一下HTTP协议的弊端以及WebSocket协议的开发使用。
Liusy
2020/08/31
9790
netty案例,netty4.1中级拓展篇五《基于Netty搭建WebSocket,模仿微信聊天页面》
本章节我们模仿微信聊天页面,开发一个基于Netty搭建WebSocket通信案例。Netty的应用方面非常广;聊天、MQ、RPC、数据等等,在5G到来的时候更加需要大量数据传输,Netty的应用也会更加广阔。
小傅哥
2020/02/14
1.3K0
netty案例,netty4.1中级拓展篇五《基于Netty搭建WebSocket,模仿微信聊天页面》
Netty基础—7.Netty实现消息推送服务
HTTP请求消息由三部分组成:请求行、请求头、请求体。HTTP响应消息也由三部分组成:响应行、响应头、响应体。
东阳马生架构
2025/05/21
1270
基于netty的websocket协议的对话小程序
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
suveng
2019/09/18
8860
基于netty的websocket协议的对话小程序
Java-WebSocket vs Netty-WebSocket 资源占用
在进行WebSocket协议连接或者WebSocket接口测试的时候,一旦遇到超大连接数量的场景中时,之前使用过的实现 Java-WebSocket 以及 Netty-WebSocket 两种实现就会显示出巨大的性能差距。当然 Netty-WebSocket 就是为了解决性能问题而来的。
FunTester
2023/10/10
6960
Java-WebSocket vs Netty-WebSocket 资源占用
WebSocket快速上手
WebSocket建立在TCP协议之上,并且与HTTP协议有着良好的兼容性,最大的特点就是服务器可以主动向客户端推送消息,客户端也可以主动向服务器发送消息。
全栈程序员站长
2022/09/18
4100
WebSocket快速上手
Netty入门之WebSocket初体验
BIO即同步阻塞模式一请求一应答的通信模型,该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,由于线程是JAVA虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能将急剧下降,随着并发访问量的继续增大,系统会发生线程堆栈溢出、创建新线程失败等问题,并最终导致进程宕机或者僵死,不能对外提供服务。
端碗吹水
2020/09/23
1K0
Netty入门之WebSocket初体验
WebSocket就是这么简单
前言 今天在慕课网上看到了Java的新教程(Netty入门之WebSocket初体验):https://www.imooc.com/learn/941 WebSocket我是听得很多,没有真正使用过的技术。我之前也去了解过了WebSocket究竟是什么东西,不过一直没有去实践过。 我在写监听器博文的时候,在线人数功能用监听器的是来做,在评论有说使用WebSocket的方式会更加好。 那么,我们就来探究一下WebSocket究竟是什么东西,顺便了解一下Netty。! WebSocket介绍 什么是WebSoc
Java3y
2018/03/15
2.6K0
WebSocket就是这么简单
websocket+netty实时视频弹幕交互功能(Java版)
来源 | https://binhao.blog.csdn.net/article/details/112631642
程序猿DD
2021/10/14
8960
Netty-Websocket 根据URL路由,分发机制的实现
最近在做netty整合websocket,发现网上很多项目都是最简单的demo,单例的一个项目。 然而公司的项目需要接受几个不同功能的ws协议消息,因此最好是用URL来区分,让页面上采用不同的链接方式。 网上项目出现地址的方法: private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { // 如果HTTP解码失败,返回HHTP异常 if(!req.decoderResult
生活创客
2018/01/30
4.2K0
Netty-Websocket 根据URL路由,分发机制的实现
netty系列之:使用netty搭建websocket服务器
websocket是一个优秀的协议,它是建立在TCP基础之上的,兼容HTTP的网络协议。通过Websocket我们可以实现客户端和服务器端的即时通讯,免除了客户端多次轮循带来的性能损耗。
程序那些事
2021/09/27
5.9K0
Netty-WebSocket 网络聊天demo教程
毕设需求,调研一下,新手来说任何项目都是从研究demo开始的(至少我这个菜鸡就这样,只能先研究研究再开始做自己的项目),这里提供了一个我最开始的demo,提供借鉴 <!--先来一下netty的 maven仓库配置需求--> <!-- https://mvnrepository.com/artifact/io.netty/netty-all --> <dependency> <groupId>io.netty</groupId> <artif
名字是乱打的
2021/12/22
5020
websocket与下位机通过netty方式通信传输行为信息
在物联网开发中,常常需要通过网页端来控制设备,包括;获取信息、执行操作、启动停止等,就像我们在手机上会控制家里的小米盒子、路由器、电饭煲或者在线养狗等一些设备一样。在这里所有的下层设备都可以通过socket通信链接到服务端,而用户一端在通过http链接或者websocket链接到服务端,通过发送和接收数据来做出相应的行为操作。如下图;
小傅哥
2020/07/14
9850
基于Netty开发Websocket服务端
Netty简介 那么Netty到底是何方神圣? 用一句简单的话来说就是:Netty封装了JDK的NIO,让你用得更爽,你不用再写一大堆复杂的代码了。 用官方正式的话来说就是:Netty是一个异步事件驱动的网络应用框架,用于快速开发可维护的高性能服务器和客户端。 下面是我总结的使用Netty不使用JDK原生NIO的原因 使用JDK自带的NIO需要了解太多的概念,编程复杂 Netty底层IO模型随意切换,而这一切只需要做微小的改动,改改参数,Netty可以直接从NIO模型变身为IO模型 Nett
码客说
2019/10/22
1.9K0
SpringBoot+Netty+WebSocket 实现消息推送
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/07/26
1.8K0
SpringBoot+Netty+WebSocket 实现消息推送
相关推荐
WebSocket vs SSE: 实时数据推送到前端的选择与实现(详细)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验