0
点赞
收藏
分享

微信扫一扫

Netty:创建WebSocket服务器和客户端


一、有点复杂的方式,自己处理协议升级、握手等信息
1.创建ServerHandler

package cn.edu.tju;

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.*;

public class MyWebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
private WebSocketServerHandshaker handshaker;
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
if(msg instanceof FullHttpRequest){
handleHttpRequest(ctx,(FullHttpRequest)msg);
}
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{
if(!req.getDecoderResult().isSuccess()||(!"websocket".equals(req.headers().get("Upgrade")))){
return;
}
WebSocketServerHandshakerFactory wsFactory=new WebSocketServerHandshakerFactory("ws://localhost:1234/websocket",null,false);
handshaker=wsFactory.newHandshaker(req);
if(handshaker==null){
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
}
else{
handshaker.handshake(ctx.channel(),req);
}
}
private void handleWebSocketFrame(ChannelHandlerContext ctx,WebSocketFrame webSocketFrame){
if(webSocketFrame instanceof CloseWebSocketFrame){
handshaker.close(ctx.channel(),(CloseWebSocketFrame)webSocketFrame.retain());
return;
}
if(webSocketFrame instanceof PingWebSocketFrame){
ctx.channel().write(new PongWebSocketFrame(webSocketFrame.content().retain()));
return;
}

String request=((TextWebSocketFrame)webSocketFrame).text();
System.out.println(ctx.channel()+" received: "+request);
ctx.channel().writeAndFlush(new TextWebSocketFrame(new java.util.Date().toLocaleString()));
}
}

2.创建WebSocket服务器:

package cn.edu.tju;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.*;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.stream.ChunkedWriteHandler;

public class WebSocketServer {
public static void main(String[] args) {
EventLoopGroup bossGroup=new NioEventLoopGroup();
EventLoopGroup workerGroup=new NioEventLoopGroup();

try{
ServerBootstrap serverBootstrap=new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline=socketChannel.pipeline();
channelPipeline.addLast(new HttpServerCodec());
channelPipeline.addLast(new HttpObjectAggregator(65536));
channelPipeline.addLast(new ChunkedWriteHandler());
channelPipeline.addLast(new MyWebSocketServerHandler());

}
});
ChannelFuture channelFuture=serverBootstrap.bind(1234).sync();
channelFuture.channel().closeFuture().sync();

}catch (Exception ex){
System.out.println(ex.getMessage());
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

二、更简便的方式,使用WebSocketServerProtocolHandler:
1.创建ServerHandler

package cn.edu.tju;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.time.LocalDateTime;

public class MyWebSocketServerHandler2 extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
Channel channel = ctx.channel();
System.out.println(channel.remoteAddress() + ": " + msg.text());
ctx.channel().writeAndFlush(new TextWebSocketFrame("来自服务端: " + LocalDateTime.now()));
}

@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("ChannelId:" + ctx.channel().id().asLongText());
}

@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("用户下线: " + ctx.channel().id().asLongText());
}

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

2.创建WebSocket服务器:

package cn.edu.tju;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.*;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

public class WebSocketServer2 {
public static void main(String[] args) {
EventLoopGroup bossGroup=new NioEventLoopGroup();
EventLoopGroup workerGroup=new NioEventLoopGroup();

try{
ServerBootstrap serverBootstrap=new ServerBootstrap();
serverBootstrap.group(bossGroup,workerGroup);
serverBootstrap.channel(NioServerSocketChannel.class);
serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {

@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline=socketChannel.pipeline();
channelPipeline.addLast(new HttpServerCodec());
channelPipeline.addLast(new ChunkedWriteHandler());
channelPipeline.addLast(new HttpObjectAggregator(8192));
channelPipeline.addLast(new WebSocketServerProtocolHandler("/websocket"));
channelPipeline.addLast(new MyWebSocketServerHandler2());

}
});
ChannelFuture channelFuture=serverBootstrap.bind(1234).sync();
channelFuture.channel().closeFuture().sync();

}catch (Exception ex){
System.out.println(ex.getMessage());
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

三、连接WebSocket的html

<!DOCTYPE HTML>
<html>
<head>
<title>WebSocket Demo</title>
</head>

<body>
<input id="text" type="text" /><br>
<button onclick="sendMessage()">发送消息</button><br>
<button onclick="closeWebSocket()">关闭连接</button>
<div id="message">
</div>
</body>

<script type="text/javascript">
var webSocket = null;

//判断WebSocket支持
if('WebSocket' in window){
webSocket = new WebSocket("ws://localhost:1234/websocket");
}
else{
alert('WebSocket is not supported');
}

//连接发生错误的回调方法
webSocket.onerror = function(){
alert('连接失败');
};

//连接成功建立的回调方法
webSocket.onopen = function(event){
alert('连接成功');
}

//接收到消息的回调方法
webSocket.onmessage = function(event){
setMessageInnerHTML(event.data);
}

//连接关闭的回调方法
webSocket.onclose = function(){
alert("连接已关闭");
}

//当窗口关闭时关闭websocket连接
window.onbeforeunload = function(){
webSocket.close();
}

//关闭连接
function closeWebSocket(){
webSocket.close();
}

//发送消息
function sendMessage(){
var message = document.getElementById('text').value;
webSocket.send(message);
}

//显示消息
function setMessageInnerHTML(innerHTML){
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}

</script>
</html>


举报

相关推荐

0 条评论