用Netty搭建一个简单的WebSocket

本文介绍了一种使用Netty框架实现WebSocket服务器的方法,包括握手处理、消息读取及响应过程,适用于搭建实时通信系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • Handler:
package com.jay.websocket;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;

import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {

    private static final Logger logger=Logger.getLogger(WebSocketServerHandler.class.getName());

    private WebSocketServerHandshaker webSocketServerHandshaker;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        //若是http接入
        if(msg instanceof FullHttpRequest)
            handleHttpRequest(ctx,(FullHttpRequest)msg);
        //如果是WebSocket接入
        else if(msg instanceof WebSocketFrame)
            handleWebSocketFrame(ctx,(WebSocketFrame)msg);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }


    private void handleHttpRequest(ChannelHandlerContext ctx,FullHttpRequest req) throws Exception{
        //如果连接失败或者不是socket连接
        if(!req.getDecoderResult().isSuccess()||(!"websocket".equals(req.headers().get("Upgrade")))){
            sendHttpResponse(ctx,req,new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
            return;
        }
        //握手工厂
        WebSocketServerHandshakerFactory wsFactory=new WebSocketServerHandshakerFactory(
                "ws://localhost:8080/websocket",null,false
        );
        //握手连接
        webSocketServerHandshaker=wsFactory.newHandshaker(req);
        if(webSocketServerHandshaker!=null){
            WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());
        }else{
            webSocketServerHandshaker.handshake(ctx.channel(),req);
        }
    }

    private void  handleWebSocketFrame(ChannelHandlerContext ctx,WebSocketFrame frame){
        if(frame instanceof CloseWebSocketFrame){
            webSocketServerHandshaker.close(ctx.channel(),(CloseWebSocketFrame)frame.retain());
            return;
        }

        if(frame instanceof PingWebSocketFrame){
            ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
            return;
        }

        if(!(frame instanceof TextWebSocketFrame)){
            throw new UnsupportedOperationException(String.format("%s frame types not supported",frame.getClass().getName()));
        }
        //获取内容
        String request=((TextWebSocketFrame)frame).text();
        if(logger.isLoggable((Level.FINE))){
            logger.fine(String.format("%s receive %s",ctx.channel(),request));

            ctx.channel().write(
                    new TextWebSocketFrame(request+
                            ",欢迎使用Netty WebSocket服务,现在时间是:"
                    +new Date().toString())
            );
        }
    }

    private static void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res){
        if(res.getStatus().code()!=200){
            ByteBuf byteBuf= Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);
            res.content().writeBytes(byteBuf);
            byteBuf.release();
        }

        ChannelFuture f=ctx.channel().writeAndFlush(res);
    }

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

  • Server:
package com.jay.websocket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
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.stream.ChunkedWriteHandler;

public class WebSocketServer {
    public void run(int port)throws Exception{
        EventLoopGroup boss=new NioEventLoopGroup();
        EventLoopGroup worker=new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap=new ServerBootstrap();
            serverBootstrap.group(boss,worker)
            .channel(NioServerSocketChannel.class)
            .childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    //将请求和应答信息编码或者解码成HTTP消息
                    socketChannel.pipeline().addLast("http-codec",new HttpServerCodec());
                    //将HTTP消息的多个部分组合成一条完整的HTTP消息
                    socketChannel.pipeline().addLast("aggregator",new HttpObjectAggregator(65536));
                    //向客户端发送HTML5文件。
                    socketChannel.pipeline().addLast("http-chunked",new ChunkedWriteHandler());
                    socketChannel.pipeline().addLast("handler",new WebSocketServerHandler());
                }
            });
            Channel channel=serverBootstrap.bind(port).sync().channel();
            System.out.println("WebSocket启动,端口为:"+ port );
            channel.closeFuture().sync();
        }finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

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

再配合html来测试就可以了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值