【Netty】简单构建服务端&客户端(web/java)

创建服务器端 Server

  Server

public class Server {
    public static void main(String[] args) {
        //bossGroup负责处理连接请求,WorkerGroup负责处理业务请求。
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup,workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //自定义处理器
                            pipeline.addLast(new ServerHandler());
                            //当客户端为Web端时需要添加以下处理
                            //websocket基于http协议,添加http的编解码器
                            pipeline.addLast(new HttpServerCodec());
                            //对http中大数据的数据流,提供写大数据流的支持
                            pipeline.addLast(new ChunkedWriteHandler());
                            //对httpMessage进行聚合处理,聚合成FullHttpRequest或FullHttpResponse
                            pipeline.addLast(new HttpObjectAggregator(1024*64));
                            /*
                             * 处理一些繁重复杂的事情;
                             * 处理websocket的握手动作:handshaking(close/ping/pong) ping+pong=心跳
                             从Http协议升级到Websocket协议,是通过StatusCode 101(Switching Protocols)来切换的。
                             * 对于websocket来说,都是以frames进行传输,不同的数据类型frames不同
                             * 并且要指定与客户端交互的路径:ws://localhost:8088/chat
                             */
                            pipeline.addLast(new WebSocketServerProtocolHandler("/chat"));
                        }
                    });
            System.out.println("服务已启动");
            //监听端口
            ChannelFuture channelFuture = bootstrap.bind(8888).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

}

 

自定义处理器 ServerHandler

//java客户端
//public class ServerHandler extends ChannelInboundHandlerAdapter{}
/**
 * 由于它的传输数据载体是frame,这个frame在netty中,是用于websocket专门处理文本对象的
 * netty中用TextWebSocketFrame对象来封装frame
 */
public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    
    //客户端组
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
//    @Override
//    public void channelRead(ChannelHandlerContext ctx,Object msg){
//        ByteBuf byteBuf = (ByteBuf) msg;
//        System.out.println("收到客户端消息:" + ctx.channel().remoteAddress() + ":" + byteBuf.toString(CharsetUtil.UTF_8));
//        String data = byteBuf.toString(CharsetUtil.UTF_8);
//        clients.writeAndFlush(new TextWebSocketFrame("[来自桌面客户端的消息" + new Date() + " ] : " + data));
//    }

    //收到客户端消息
    @Override
    public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg){
        String text = msg.text();
        System.out.println("收到客户端消息:" + ctx.channel().remoteAddress() + ":" + text);
        clients.writeAndFlush(new TextWebSocketFrame("【" + ctx.channel().remoteAddress().toString() + "】:" + text));
    }

    /**
    *  服务器接收到客户端的消息后,给客户端返回消息
    */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx){
//        ctx.writeAndFlush(Unpooled.copiedBuffer("收到了客户端的消息",CharsetUtil.UTF_8));
    }

    //客户端加入
    @Override
    public void handlerAdded(ChannelHandlerContext ctx){
        System.out.println("有新客户端连接进入:" + ctx.channel().remoteAddress());
        clients.add(ctx.channel());
    }

    //出现异常,可加入日志
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
        ctx.close();
    }

    //客户端离开
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx){
        System.out.println("有客户端离开:" + ctx.channel().remoteAddress());
    }
}

 

Web 客户端

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>Netty通信</title>
	</head>
	<body>
		发送消息:<input type="text" id="msgContent"/>
		<input type="button" value="发送消息" onclick="CHAT.chat()" />
		<hr />
		接受消息:
		<div id="receiveMsg"></div>
		
		
		<script type="text/javascript">
			window.CHAT = {
				socket:null,
				//初始化socket
				init:function(){
					//判断浏览器是否支持websocket
					if(window.WebSocket){
						//创建websocket对象
						CHAT.socket = new WebSocket("ws://127.0.0.1:8888/chat");
						
						CHAT.socket.onopen = function(){
							console.log("连接建立成功");
						},
						CHAT.socket.close = function(){
							console.log("连接关闭");
						},
						CHAT.socket.onerror = function(){
							console.log("发生异常");
						},
						CHAT.socket.onmessage = function(e){
							console.log("接受消息:"+e.data);
							var receiveMsg = document.getElementById("receiveMsg");
							var html = receiveMsg.innerHTML; //获取本对象原有的内容
							//嵌入新的内容
							receiveMsg.innerHTML = html + "<br/>" + e.data;
						}
					}else{
						console.log("浏览器不支持websocket协议");
					}
				},
                //发送消息时触发的函数
				chat:function(){
					//获取消息框中所输入的内容
					var msgContent = document.getElementById("msgContent").value;
					//将客户端输入的消息进行发送
					CHAT.socket.send(msgContent);
				}
			};
			
			CHAT.init();
			
		</script>
		
	</body>
</html>

 

java 客户端

   客户端启动

public class Client {

    public static void main(String[] args) {
        NioEventLoopGroup eventExecutors = new NioEventLoopGroup();

        try {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(eventExecutors)
                    .channel(NioSocketChannel.class)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            //自定义处理器
                            pipeline.addLast(new ClientHandler());
                        }
                    });
            System.out.println("客户端已启动");
            //连接服务器
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1",8888).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            //销毁
            eventExecutors.shutdownGracefully();
        }
    }
}

客户端自定义处理器

public class ClientHandler extends ChannelInboundHandlerAdapter {

    
    @Override
    public void channelActive(ChannelHandlerContext ctx){
        String substring = UUID.randomUUID().toString().replace("-", "").substring(5, 10);
        ctx.writeAndFlush(Unpooled.copiedBuffer("你好服务器,我是客户端" + substring, CharsetUtil.UTF_8));
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx,Object msg){
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("收到服务器的消息:" + ctx.channel().remoteAddress() + ": " + byteBuf.toString(CharsetUtil.UTF_8));
    }
}

 

posted @ 2022-10-25 17:59  YanSss  阅读(255)  评论(0编辑  收藏  举报