netty 实现websocket

1先加入jar

io.netty
netty-all
5.0.0.Alpha2

2编写WebSocketServerHandler
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.Constant;

import java.io.IOException;
import java.util.*;

public class WebSocketServerHandler extends SimpleChannelInboundHandler {
private WebSocketServerHandshaker handshaker;
private Map map = new HashMap();

/**
 * 接收客户端发送的消息
 *
 * @param channelHandlerContext ChannelHandlerContext
 * @param receiveMessage        消息
 */
@Override
protected void messageReceived(ChannelHandlerContext channelHandlerContext, Object receiveMessage) throws Exception {
    // 传统http接入 第一次需要使用http建立握手
    if (receiveMessage instanceof FullHttpRequest) {
        FullHttpRequest fullHttpRequest = (FullHttpRequest) receiveMessage;
        //  LOGGER.info("├ [握手]: {}", fullHttpRequest.uri());
        // 握手
        handlerHttpRequest(channelHandlerContext, fullHttpRequest);
        // 发送连接成功给客户端
        channelHandlerContext.channel().write(new TextWebSocketFrame("连接成功------------------"));
    }
    // WebSocket接入
    else if (receiveMessage instanceof WebSocketFrame) {
        WebSocketFrame webSocketFrame = (WebSocketFrame) receiveMessage;
        handlerWebSocketFrame(channelHandlerContext, webSocketFrame);
    }
}

/**
 * 第一次握手
 *
 * @param channelHandlerContext channelHandlerContext
 * @param req                   请求
 */
private void handlerHttpRequest(ChannelHandlerContext channelHandlerContext, FullHttpRequest req) {
    // 构造握手响应返回,本机测试
    WebSocketServerHandshakerFactory wsFactory
            = new WebSocketServerHandshakerFactory("ws://localhost:8080", null, false);
    // region 从连接路径中截取连接用户名
    String uri = req.uri();
    int i = uri.lastIndexOf("/");
    String userName = uri.substring(i + 1, uri.length());
    // endregion
    Channel connectChannel = channelHandlerContext.channel();
    // 加入在线用户
    map.put(userName, connectChannel);
    handshaker = wsFactory.newHandshaker(req);
    if (handshaker == null) {
        // 发送版本错误
        WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(connectChannel);
    } else {
        // 握手响应
        handshaker.handshake(connectChannel, req);
    }
}

/**
 * webSocket处理逻辑
 *
 * @param channelHandlerContext channelHandlerContext
 * @param frame                 webSocketFrame
 */
private void handlerWebSocketFrame(ChannelHandlerContext channelHandlerContext, WebSocketFrame frame) throws IOException {
    Channel channel = channelHandlerContext.channel();
    // region 判断是否是关闭链路的指令
    if (frame instanceof CloseWebSocketFrame) {
        // LOGGER.info("├ 关闭与客户端[{}]链接", channel.remoteAddress());
        handshaker.close(channel, (CloseWebSocketFrame) frame.retain());
        return;
    }
    // endregion
    // region 判断是否是ping消息
    if (frame instanceof PingWebSocketFrame) {
        // LOGGER.info("├ [Ping消息]");
        channel.write(new PongWebSocketFrame(frame.content().retain()));
        return;
    }
    // endregion
    // region 纯文本消息
    if (frame instanceof TextWebSocketFrame) {
        String text = ((TextWebSocketFrame) frame).text();
        //  LOGGER.info("├ [{} 接收到客户端的消息]: {}", new Date(), text);
        channel.writeAndFlush(new TextWebSocketFrame("服务器返回消息:" + new Date()));
        System.out.println("消息已经返回");
    }
    // endregion
    // region 二进制消息 此处使用了MessagePack编解码方式

// if (frame instanceof BinaryWebSocketFrame) {
// BinaryWebSocketFrame binaryWebSocketFrame = (BinaryWebSocketFrame) frame;
// ByteBuf content = binaryWebSocketFrame.content();
// // LOGGER.info("├ [二进制数据]:{}", content);
// final int length = content.readableBytes();
// final byte[] array = new byte[length];
// content.getBytes(content.readerIndex(), array, 0, length);
// MessagePack messagePack = new MessagePack();
// WebSocketMessageEntity webSocketMessageEntity = messagePack.read(array, WebSocketMessageEntity.class);
// // LOGGER.info("├ [解码数据]: {}", webSocketMessageEntity);
// WebSocketUsers.sendMessageToUser(webSocketMessageEntity.getAcceptName(), webSocketMessageEntity.getContent());
// }
// endregion
}
}
3WebSocketServer 单独一个线程启动即可
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
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.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.stream.ChunkedWriteHandler;

public class WebSocketServer {
public void run(int port) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workGroup).channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
//转化为http消息
pipeline.addLast("http-codec", new HttpServerCodec());
//多个分组组合一条http消息
pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
//写入客户端
pipeline.addLast("http-chunked", new ChunkedWriteHandler());
pipeline.addLast("handler", new WebSocketServerHandler());
}
});
Channel ch = b.bind(port).sync().channel();
ch.closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}

}

public static void main(String[] args) {
    int port = 8080;
    new WebSocketServer().run(port);
}

}
4html




菜鸟教程(runoob.com)





运行结果截图


image.png

你可能感兴趣的:(netty 实现websocket)