Netty框架实现简单的客户端与服务端通信案例(附IDEA中可运行代码)

            首先确保引入了netty的jar包(4.1.20版的netty),我是通过IDEA内部的Maven下的,因为这样可以将jar包直接放入项目的lib目录中,简单方便。还没下载的朋友可以看看:

一、打开Project Structure,并点击Modules模块:

 

 二、输入io.netty:netty-all后点击搜索按钮,记得要保证IDEA连网,并且要耐心等一会儿,毕竟它不会一下就显示搜索结果,然后选择4.1.20版本的下载,初次下载比较慢。

 

附上IDEA中可运行工程的结构:

话不多说,开始撸代码!因为代码中已经有了必要的注释,因此不再作其它解释了。

NettyServer.java

package simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        //创建两个线程组:BossGroup:处理连接请求和WorkerGroup:真正与客户端业务处理,两个都是无限循环
        EventLoopGroup BossGroup = new NioEventLoopGroup();
        EventLoopGroup WorkerGroup = new NioEventLoopGroup();

        try {
            //创建服务器端的启动对象,配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();
            //使用链式编程来进行设置
            bootstrap.group(BossGroup, WorkerGroup)//设置两个线程组
                    .channel(NioServerSocketChannel.class)//使用NIOSocketChannel作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128)//设置线程队列得到连接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true)//设置保持活动连接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() {//创建一个通道初始化对象(匿名对象)
                        //给pipline设置处理器
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new NettyServerHandler());
                        }
                    });//给我们EventGroup对应的管道设置处理器

            System.out.println("服务器is ready!");

            //绑定一个端口并同步,生成了一个ChannelFuture对象
            //启动服务器(并绑定端口)
            ChannelFuture channelFuture = bootstrap.bind(6668).sync();

            //对关闭通道进行监听
            channelFuture.channel().closeFuture().sync();
        }finally {
            BossGroup.shutdownGracefully();
            WorkerGroup.shutdownGracefully();
        }
    }
}

NettyServerHandler.java

package simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

import java.nio.charset.Charset;

//我们自定义一个handler需要继续netty规定好的某个HandlerAdapter(规范)
//这时我们制定的一个handler,才能称为一个handler

public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    //这里我们可以读取客户端发送的消息
    /*
    1.ChannelHandlerContext ctx:上下文对象,含有管道pipline,通道channel,地址
    2.Object msg默认是客户端发送的消息,默认Object
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("server ctx=" +ctx);
        //将msg转成byteBuf
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("客户端发送消息是" + byteBuf.toString(CharsetUtil.UTF_8));
        System.out.println("客户端地址是:"+ ctx.channel().remoteAddress());
    }

    //数据读取完毕
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        //writeAndFlush是write方法+Flush方法,将数据写入到缓存并刷新
        //一般来讲我们对发送的数据进行编码
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello客户端", CharsetUtil.UTF_8));
    }

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

 

---------------------------------------------------------分割线:以上是服务端,接下来写客户端---------------------------------------------------

NettyClient.java

package simple;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
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.NioSocketChannel;

public class NettyClient {
    public static void main(String[] args) throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();
        try{
        //创建客户端启动对象,注意客户端使用的不是ServerBootStrap而是BootStrap
        Bootstrap bootstrap = new Bootstrap();
        //设置相关参数
        bootstrap
                .group(group)//设置线程组
                .channel(NioSocketChannel.class)//设置客户端通道的实现类
                .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new NettyClientHandler());
                    }
                });
        System.out.println("客户端OK");
        //启动客户端去连接服务器端
        //关于channel要分析,要分析netty的异步模型
        ChannelFuture channelfulture = bootstrap.connect("127.0.0.1", 6668).sync();
        channelfulture.channel().closeFuture().sync();
    }finally {
        group.shutdownGracefully();
        }
        }
}

NettyClientHandler.java

package simple;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

public class NettyClientHandler extends ChannelInboundHandlerAdapter {
    @Override
    //当通道就绪就会触发该方法
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("clinet" + ctx);
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello,Server",CharsetUtil.UTF_8));
    }

    //当通道有读取事件时会触发
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf byteBuf = (ByteBuf) msg;
        System.out.println("服务器回复的消息:" + byteBuf.toString(CharsetUtil.UTF_8));
        System.out.println("服务器的地址:" + ctx.channel().remoteAddress());
    }

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

OK,接着先运行服务端,再运行客户端,就可以看到控制台输出信息。

服务端输出:

客户端输出:

 

             欧拉,到此为止结束。认可此篇的朋友,懂我的意思吧?麻烦三连┗|`O′|┛ ~,点赞、关注、收藏~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单Netty实现WebSocket协议的服务客户案例服务代码: ```java 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.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; public class WebSocketServer { private final int port; public WebSocketServer(int port) { this.port = port; } public void start() throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap() .group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new HttpObjectAggregator(65536)); pipeline.addLast(new WebSocketServerProtocolHandler("/websocket")); pipeline.addLast(new WebSocketServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture future = bootstrap.bind(port).sync(); System.out.println("WebSocket Server started on port " + port); future.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new WebSocketServer(8080).start(); } } ``` 客户代码: ```java import io.netty.bootstrap.Bootstrap; import io.netty.channel.*; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.*; import io.netty.handler.codec.http.websocketx.*; import io.netty.util.CharsetUtil; import java.net.URI; public class WebSocketClient { private final URI uri; private final WebSocketClientHandler handler = new WebSocketClientHandler(); private Channel channel; public WebSocketClient(URI uri) { this.uri = uri; } public void start() throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap() .group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new HttpClientCodec()); pipeline.addLast(new HttpObjectAggregator(8192)); pipeline.addLast(new WebSocketClientProtocolHandler(uri, WebSocketVersion.V13, null, true, HttpHeaders.EMPTY_HEADERS, 65536)); pipeline.addLast(handler); } }); channel = bootstrap.connect(uri.getHost(), uri.getPort()).sync().channel(); handler.handshakeFuture().sync(); System.out.println("WebSocket Client connected to " + uri); } catch (Exception e) { group.shutdownGracefully(); } } public void stop() { channel.writeAndFlush(new CloseWebSocketFrame()); try { channel.closeFuture().sync(); } catch (InterruptedException e) { e.printStackTrace(); } } public void sendMessage(String message) { channel.writeAndFlush(new TextWebSocketFrame(message)); } public static void main(String[] args) throws Exception { WebSocketClient client = new WebSocketClient(new URI("ws://localhost:8080/websocket")); client.start(); client.sendMessage("Hello, Netty WebSocket!"); Thread.sleep(1000); client.stop(); } private static class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> { private final WebSocketClientHandshaker handshaker; private ChannelPromise handshakeFuture; public WebSocketClientHandler() { URI uri = URI.create("ws://localhost:8080/websocket"); handshaker = WebSocketClientHandshakerFactory.newHandshaker(uri, WebSocketVersion.V13, null, true, HttpHeaders.EMPTY_HEADERS, 65536); } public ChannelFuture handshakeFuture() { return handshakeFuture; } @Override public void handlerAdded(ChannelHandlerContext ctx) { handshakeFuture = ctx.newPromise(); } @Override public void channelActive(ChannelHandlerContext ctx) { handshaker.handshake(ctx.channel()); } @Override public void channelInactive(ChannelHandlerContext ctx) { System.out.println("WebSocket Client disconnected!"); } @Override public void channelRead0(ChannelHandlerContext ctx, Object msg) { Channel ch = ctx.channel(); if (!handshaker.isHandshakeComplete()) { handshaker.finishHandshake(ch, (FullHttpResponse) msg); System.out.println("WebSocket Client connected!"); handshakeFuture.setSuccess(); return; } if (msg instanceof FullHttpResponse) { FullHttpResponse response = (FullHttpResponse) msg; throw new IllegalStateException( "Unexpected FullHttpResponse (getStatus=" + response.status() + ", content=" + response.content().toString(CharsetUtil.UTF_8) + ')'); } WebSocketFrame frame = (WebSocketFrame) msg; if (frame instanceof TextWebSocketFrame) { TextWebSocketFrame textFrame = (TextWebSocketFrame) frame; System.out.println("WebSocket Client received message: " + textFrame.text()); } else if (frame instanceof PongWebSocketFrame) { System.out.println("WebSocket Client received pong"); } else if (frame instanceof CloseWebSocketFrame) { System.out.println("WebSocket Client received closing"); ch.close(); } } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); if (!handshakeFuture.isDone()) { handshakeFuture.setFailure(cause); } ctx.close(); } } } ``` 使用时,先启动服务,再启动客户客户启动后,会向服务发送一条消息,并在接收到服务的响应后关闭连接。在控制台上可以看到客户服务的交互过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值