netty学习(四) - 初试webSocket

4 篇文章 0 订阅

webSocket 是在H5上提出的规范,它可以解决很多以前http无法做到的事情,比如:

  1. 每次请求都要携带cookie、一大堆请求头信息
  2. 只能客户端主动调用服务端方法,不能从服务端往客户端推送数据

服务端

public class WebSocketServer {

    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup boosGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boosGroup, workerGroup).channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    // 因为webSocket 连接的建立过程是首先通过http的请求建立连接,
                    // 当请求成功后将协议切换并且升级,所以服务器上要有Http的支持
                    pipeline.addLast(new HttpServerCodec());
                    // 数据以块的形式处理
                    pipeline.addLast(new ChunkedWriteHandler());
                    // 针对于http的请求 对请求对象进行聚合 也是http开发中最常用的处理器
                    // 当使用此处理器之后 请求参数的类型就会转换成为FullHttpRequest/FullHttpResponse(根据是接收消息还是发送消息选择)
                    pipeline.addLast(new HttpObjectAggregator(4096));
                    // 真正处理webSocket的处理器
                    // 参数 指定项目路径 相当于web项目中的context-path
                    // eg: ws://localhost:8899/netty-ws
                    pipeline.addLast(new WebSocketServerProtocolHandler("/netty-ws"));

                    // 添加自定义的处理器
                    pipeline.addLast(new TextWebSocketFrameHandler());

                }
            });
            ChannelFuture channelFuture = bootstrap.bind(8899).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            boosGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        // 获取服务器当前时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("收到消息:" + msg.text());
        // 向客户端返回消息的时候不能直接使用writeAndFlush 了
        // 需要使用WebSocketFrame的子类包装返回消息
        ctx.writeAndFlush(new TextWebSocketFrame("服务器:" + now));
    }


    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        System.out.println("连接接入:" + channel.remoteAddress() + " channelId:" + channel.id().asLongText());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        System.out.println("连接断开:" + channel.remoteAddress() + " channelId:" + channel.id().asLongText());
    }
}

客户端

因为webSocket 是针对于web服务,所以
我们可以用常用的浏览器来作为客户端,所以我们只用编写一个html文件即可

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket</title>
</head>
<body>

<form onsubmit="return false">
    <textarea name="message" style="width:500px;height:200px;"></textarea>
    <input type="button" value="发送" onclick="send(this.form.message.value)"/>
    <h3>服务器消息</h3>
    <textarea name="responseText" id="responseText" style="width:500px;height:300px;">
    </textarea>
    <input type="button" value="连接" onclick="connectWebSocket()"/>
    <input type="button" value="断开" onclick="closeWebSocket()"/>

</form>
<script type="text/javascript">
    var webSocket;
    function connectWebSocket() {
    	// 判断浏览器是否支持webSocket 
        if (window.WebSocket) {
            webSocket = new WebSocket("ws://localhost:8899/netty-ws")
            webSocket.onopen = function () {
                var el = document.getElementById("responseText")
                el.value = "成功与服务器建立连接\n"
            }
            webSocket.onclose = function () {
                var el = document.getElementById("responseText")
                el.value = el.value + "断开连接\n"
            }

            webSocket.onmessage = function (event) {
                var el = document.getElementById("responseText")
                el.value = el.value + event.data + "\n"
            }

        }
    }
    function send(msg) {
        webSocket &&  webSocket.readyState == WebSocket.OPEN &&  webSocket.send(msg)
    }
    function closeWebSocket() {
        webSocket && webSocket.close()
    }
</script>
</body>
</html>

实现效果

客户端

在这里插入图片描述

服务端

在这里插入图片描述

总结

服务端向客户端发送消息

服务端往客户端发送消息,需要将消息使用WebSocketFrame的子类进行包装,否则会发不出去。

 		// 需要使用WebSocketFrame的子类包装返回消息
        ctx.writeAndFlush(new TextWebSocketFrame("服务器:" + now));

针对于webSocket的规范 netty均提供了对于的frame类。
在这里插入图片描述

浏览器F12 中的Network中的内容很丰富

在这里插入图片描述

在Header后面的Frames里面我们可以看到客户端和服务器交互的所有数据
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值