基于Netty的Websocket实现

目录

目录

WS协议简介

服务器实现类

服务端

业务处理器

客户端实现

基于HTML5实现

基于OKHttp的实现



WS协议简介

HTTP协议是半双工通信,同一时刻只有一个方向上的数据传送,基于请求-响应式工作模式,只能客户端主动向服务器发请求,服务器无法向客户端主动发请求,而WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。它有以下特点:

  • 单一的TCP连接,采用全双工模式通信
  • 无头部信息、Cookie和身份验证
  • 服务器可双主动发送消息给客户端,不需要客户端轮询
  • 通过ping/pong 帧保持链接激活

 

服务器实现类

 

服务端

public class WebsocketServer {

    private int port;
    public WebsocketServer(int port){
        this.port = port;
    }
    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGoup = new NioEventLoopGroup(8);
        try{
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGoup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.DEBUG))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            // websocket协议是基于http之上的升级,因此加入HttpServerCodec
                            pipeline.addLast(new HttpServerCodec());
                            // 以块进行写操作,因此加入ChunkedWriteHandler
                            pipeline.addLast(new ChunkedWriteHandler());
                            // http数据在传输过程中会分段,因此加入 HttpObjectAggregator将多个段聚合
                            pipeline.addLast(new HttpObjectAggregator(4096));
                            // 加入websocket协议处理器,将 http 协议升级为 ws 协议 , 保持长连接
                            pipeline.addLast(new WebSocketServerProtocolHandler("/chat"));
                            // 加入业务处理器
                            pipeline.addLast(new MyTextWebSocketFrame());
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(7777).sync();
            channelFuture.channel().closeFuture().sync();
        }finally {
            bossGroup.shutdownGracefully();
            workerGoup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws Exception {
        new WebsocketServer(7777).run();
    }
}

业务处理器

public class MyTextWebSocketFrame extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    @Override
    public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        System.out.println("服务器收到消息 " + msg.text());
        // 回复消息
        ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器回复消息:你好,"
                + ctx.channel().remoteAddress().toString()
                +"当前时间是" + LocalDateTime.now() ));
    }

    // 当 web 客户端连接后, 触发方法
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        System.out.println(channel.id().asLongText() + "加入了");

    }

    // 当 web 客户端断开连接后, 触发方法
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        System.out.println(channel.id().asLongText() + "离开了");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}

 

 

客户端实现

 

基于HTML5实现

客户端使用HTML5内置的WebSocket对象进行与服务端通信

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Websocket客户端</title>
    <script type="text/javascript">
        var websocket;
        if (window.WebSocket){
            // 创建ws连接
            websocket = new WebSocket("ws://localhost:7777/chat")
            websocket.open = function(ev){
                // 提示连接建立
                let responseContent = document.getElementById("responseContent");
                responseContent.value += ("\n连接建立。。。")
            }
            websocket.onmessage = function (ev) {
                // 回显内容到页面
                let responseContent = document.getElementById("responseContent");
                responseContent.value += ("\n" + ev.data)

            }
            websocket.close = function (ev) {
                // 提示连接断开
                let responseContent = document.getElementById("responseContent");
                responseContent.value += ("\n连接断开。。。")
            }
        }else{
            alert("当前浏览器不支持 websocket")
        }
        function sendMsg() {
            let sendContent = document.getElementById("sendContent");
            let content = sendContent.value
            alert(content)
            if(!window.websocket)return
            if (websocket.readyState == WebSocket.OPEN){
                // 通过websocket发送消息到服务器
                websocket.send(content)
            }else{
                alert("连接没有建立")
            }
        }
    </script>
</head>

<body>
<form  onsubmit="return false">
    <label>消息:</label><input id="sendContent" size="80" ></input><button onclick="sendMsg()">发送</button><br/>

    <label>响应:</label><textarea id="responseContent" cols="80"  rows="10" ></textarea><br/>
</form>
</body>
</html>

基于OKHttp的实现

在安卓移动应用开发中,网络请求框架okhttp已支持Websocket,因此我们使用okhttp创建websocket客户端

public class WebsocketClient {
    OkHttpClient client = null;
    public WebsocketClient(){
        client = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                //允许失败重试
                .readTimeout(5, TimeUnit.SECONDS)
                //设置读取超时时间
                .writeTimeout(5, TimeUnit.SECONDS)
                //设置写的超时时间
                .connectTimeout(5, TimeUnit.SECONDS)
                //设置连接超时时间
                .build();
    }

    public void send(){

        Request request  = new Request.Builder().url("ws://localhost:7777/chat").build();
        WebSocket webSocket = client.newWebSocket(request, new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
                super.onOpen(webSocket, response);
                //连接成功
            }

            @Override
            public void onMessage(WebSocket webSocket, String text) {
                super.onMessage(webSocket, text);
                //接收服务器消息 text
                System.out.println("服务器响应:" + text);
            }

            @Override
            public void onMessage(WebSocket webSocket, ByteString bytes) {
                super.onMessage(webSocket, bytes);
                //如果服务器传递的是byte类型的
                String msg = bytes.utf8();
                System.out.println("服务器响应:" + msg);
            }

            @Override
            public void onFailure(WebSocket webSocket, Throwable t,  Response response) {
                super.onFailure(webSocket, t, response);
                //连接失败调用 异常信息t.getMessage()
                t.printStackTrace();
            }
        });

        client.dispatcher().executorService().shutdown();//内存不足时释放
        boolean rs = webSocket.send("发送的消息");
        if (rs){
            System.out.println("发送完毕!");
        }
    }
    public static void main(String[] args) throws Exception {
        new WebsocketClient().send();
    }

}

 

Spring Boot是一个快速开发框架,Netty是一个高性能的网络通信框架,WebSocket是一种基于TCP协议的双向通信协议。将它们结合起来实现IM系统是一种非常好的选择。 以下是实现步骤: 1. 创建Spring Boot项目,添加NettyWebSocket依赖。 2. 创建WebSocket处理器,继承自Netty的SimpleChannelInboundHandler,并实现WebSocketServerProtocolHandler.ServerHandshakeStateEvent事件。在这个处理器中,可以处理连接建立、消息发送和接收等操作。 3. 创建WebSocket服务器,使用Netty的ServerBootstrap和EventLoopGroup创建一个监听端口的服务器。在服务器启动时,将WebSocket处理器添加到ChannelPipeline中。 4. 创建WebSocket客户端,使用Netty的Bootstrap和EventLoopGroup创建一个连接到服务器的客户端。在客户端连接成功时,发送握手请求,并在握手成功后发送消息。 5. 在Spring Boot项目中创建一个消息处理器,用于处理从WebSocket客户端接收到的消息。可以使用Spring的消息队列来处理这些消息。 6. 在Web界面上添加WebSocket客户端,使用JavaScript编写WebSocket客户端代码,连接到服务器并发送消息。在收到服务器发送的消息时,将其显示在Web界面上。 通过以上步骤,就可以实现一个基于Spring Boot、NettyWebSocket的IM系统。用户可以在Web界面上发送和接收消息,服务器和客户端之间的通信是双向的。这种实现方式具有高性能、高可靠性和高扩展性,可以应用于各种实时通信场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值