服务端

public class Server {
private final int port;

public Server(int port) {
this.port = port;
}

public void run() {
//创建两个事件循环组,bossGroup只处理连接请求,workGroup处理客户端业务处理,交给bossGroup
//两个都是无线循环
//默认CPU核*2
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();

try {
//创建服务端启动对象,配置参数
ServerBootstrap bootstrap = new ServerBootstrap();

//用链式编程进行设置
bootstrap.group(bossGroup, workGroup)//设置两个线程组
.channel(NioServerSocketChannel.class)//使用NioSocketChannel作为服务器通道实现
//.option(ChannelOption.SO_BACKLOG, 128)//设置线程队列个数
//.childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接状态
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel channel) throws Exception {
ChannelPipeline pipeline = channel.pipeline();
//http编码与解码器
pipeline.addLast(new HttpServerCodec())
//以块方式写
.addLast(new ChunkedWriteHandler())
//http在传输中是分段的,HttpObjectAggregator可以将多个分段聚合起来
//当浏览器发送大量数据时,会发出多次http请求
.addLast(new HttpObjectAggregator(8192))
//对于websocket,它的数据时以帧(frame)形式传递
//可以看到webSocketFrame下面有六个子类
//浏览器请求时是webSocket所以是ws开头的,如ws://localhost:666/hello,与如下WebSocketServerProtocolHandler对应
//WebSocketServerProtocolHandler核心功能是将http协议升级为ws协议,保持长连接
.addLast(new WebSocketServerProtocolHandler("/hello"))
//自定义handler,处理业务逻辑
.addLast(new ServerHandler());
}
});//给workGroup的EventLoop对应的管道设置处理器

//启动服务器,绑定端口,生成ChannelFuture对象
ChannelFuture future = bootstrap.bind(port).sync();
//对关闭通道进行监听(非阻塞监听,异步模型)
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
}

public static void main(String[] args) throws InterruptedException {
new Server(666).run();
}
}

服务端Handler

//SimpleChannelInboundHandler继承HandlerAdapter
//TextWebSocketFrame表示一个文本帧(frame)
public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
System.out.println("服务端收到消息" + msg.text());
//回复消息
ctx.channel().writeAndFlush(new TextWebSocketFrame("服务器时间" + LocalDateTime.now() + msg.text()));
}

//建立连接,触发此事件
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//LongText唯一的
System.out.println("handlerAdded被调用" + ctx.channel().id().asLongText());
//ShortText不是唯一的
System.out.println("handlerAdded被调用" + ctx.channel().id().asShortText());
}

//断开连接,触发此事件,将离开信息推送给在线客户
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerRemoved被调用" + ctx.channel().id().asLongText());
}

//处理异常,关闭通道
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}

HTML页面

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello</title>
</head>
<body>
<script>
var socket;
//判断浏览器是否支持websocket
if (window.WebSocket) {
socket = new WebSocket("ws://localhost:666/hello");
//相当于channelRead0,ev收到服务器端回送的消息
socket.onmessage = function (ev) {
var rt = document.getElementById("responseText");
rt.value = rt.value + "\n" + ev.data;
}
//相当于连接开启
socket.onopen = function (ev) {
var rt = document.getElementById("responseText");
rt.value = "连接开启了...";
}
//感觉到连接关闭
socket.onclose = function (ev) {
var rt = document.getElementById("responseText");
rt.value = rt.value + "\n" + "连接关闭了...";
}
} else {
alert("浏览器不支持WebSocket")
}

function send(msg) {
//判断socket是否创建好
if (!window.socket) {
return;
}
if (socket.readyState == WebSocket.OPEN) {
//通过socket发送消息
socket.send(msg)
} else {
alert("连接没有开启")
}
}
</script>
<form onsubmit="return false">
<textarea name="message" style="width: 200px;height: 100px;"></textarea>
<input type="button" value="发送" onclick="send(this.form.message.value)">
<textarea id="responseText" style="width: 200px;height: 100px;"></textarea>
<input type="button" value="清空" onclick="document.getElementById('responseText').value=''">
</form>
</body>
</html>

效果

Netty websocket长连接_bootstrap

Netty websocket长连接_websocket_02