Netty——简单的入门代码示例


上一章已经介绍了纯Java几种网络IO的开发步骤及示例,毫无疑问最好的就是NIO,这也是目前最主流的方式,但是这玩意编写复杂,拓展性也不强,在通信上方方面面都需要重写,这不是一般人能搞得定了,所以呀我们得会用框架呀,Netty就是这方面框架中的佼佼者!

基础示例入门

服务端

NettyServer.class

@Slf4j
public class NettyServer{

    //1.创建线程组  bossGroup:连接线程   workGroup:工作线程
    private final NioEventLoopGroup bossGroup = new NioEventLoopGroup();
    private final NioEventLoopGroup workerGroup = new NioEventLoopGroup();

    public void serverStart() throws InterruptedException {
        try{
            // 服务端启动类
            ServerBootstrap bootstrap = new ServerBootstrap();
            // 传入两个线程组
            bootstrap.group(bossGroup, workerGroup)
                    // 指定Channel 和NIO一样是采用Channel通道的方式通信 所以需要指定服务端通道
                    .channel(NioServerSocketChannel.class)
                    //使用指定的端口设置套接字地址
                    .localAddress(new InetSocketAddress(11111))

                    //服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
                    .option(ChannelOption.SO_BACKLOG, 1024)

                    //设置数据处理器
                    .childHandler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel channel) throws Exception {
                            // 在管道中 添加数据处理类
                            channel.pipeline().addLast(new NettyServerTestHandler());
                        }
                    });
            // 同步等待成功
            ChannelFuture future = bootstrap.bind().sync();
            if (future.isSuccess()) {
                log.info("启动 Netty Server 成功");
            }
            //等待服务端监听端口关闭 链路关闭后main函数才会结束
            future.channel().closeFuture().sync();
        }finally {
            // 优雅的关闭 释放资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new NettyServer().serverStart();
    }
}

看上去好多,感觉比NIO还麻烦?其实很方便的:

  1. 实例化一个服务端 ServerBootstrap ,这个NIO也一样,Netty帮我们封装了
  2. 设置两个线程组,一个处理客户端连接事件,一个处理连接后数据处理事件
  3. 指定服务端通道类型,并绑定地址
  4. 设置传输的一些配置参数(这里有很多可以设置,所以拓展性强)
  5. 设置数据处理器,这里实际是添加了一个数据处理管道,管道内可以有很多数据处理类,所以可以一层一层处理,可插拔式设计(类似拦截器链)
channel.pipeline() : 这就是管道
new NettyServerTestHandler() : 这个就是管道里的一个数据处理类

// 数据处理类可以有多个
  1. 最后启动

ServerBootstrap 实例化后,都是采用建造者模式设置的,对于我们来说是非常的方便的,这里配置好后我们的重心就可以放在数据处理类上了

NettyServerTestHandler.class

NettyServerTestHandler 就是数据处理类,所有的方法都帮我们封装好了,我们不需要考虑其中调用的问题,方法是处理什么事件的,我们写对应的逻辑就好了,方法上的ChannelHandlerContext 可以理解为管道中所有数据处理类的纽带,比如拦截器链不也有么

@Slf4j
public class NettyServerTestHandler extends ChannelInboundHandlerAdapter {

    // 读取信息调用
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 和NIO一样有缓冲区 ByteBuf就是对ByteBuffer做了一层封装
        ByteBuf msg1 = (ByteBuf) msg;
        log.info("客户端信息:" + msg1.toString(CharsetUtil.UTF_8));


    }

    // 连接事件 连接成功调用
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        SocketAddress socketAddress = ctx.channel().remoteAddress();
        log.info(socketAddress + " 已连接");

        // 发送数据
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Client", CharsetUtil.UTF_8));
    }

    // 断开连接调用
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info(ctx.channel().remoteAddress() + " 已断开连接");
    }

    // 读取信息完成事件  信息读取完成后调用
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

    }

    // 异常处理  发生异常调用
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        // 异常后 关闭与客户端连接
        ctx.close();
    }
}

客户端

NettyClient.class

客户端启动和服务端几乎一致,只不过启动类成了Bootstrap ,而且我还加入了一个断连逻辑

@Slf4j
public class NettyClient  {
    private EventLoopGroup group = new NioEventLoopGroup();
    private int port=11111;
    private String host="127.0.0.1";

    public void start() throws InterruptedException {
        try{
            Bootstrap bootstrap = new Bootstrap();
            // 客户端不需要处理连接 所以一个线程组就够了
            bootstrap.group(group)
                    // 连接通道
                    .channel(NioSocketChannel.class)
                    .remoteAddress(host, port)
                    .option(ChannelOption.TCP_NODELAY, true)
                    // 数据处理
                    .handler(new ChannelInitializer<Channel>() {
                        @Override
                        protected void initChannel(Channel channel) throws Exception {
                            channel.pipeline().addLast(new NettyClientTestHandler());
                        }
                    });
            ChannelFuture future = bootstrap.connect();
            //客户端断线重连逻辑
            future.addListener((ChannelFutureListener) future1 -> {
                if (future1.isSuccess()) {
                    log.info("连接Netty服务端成功");
                } else {
                    log.info("连接失败,进行断线重连");
                    future1.channel().eventLoop().schedule(() -> {
                        try {
                            start();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }, 20, TimeUnit.SECONDS);
                }
            });
            future.channel().closeFuture().sync();
        }catch (Exception e){
            log.info("服务端异常");
        }finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new NettyClient().start();
    }
}

NettyClientTestHandler.class

数据处理类也是一样的

@Slf4j
public class NettyClientTestHandler extends ChannelInboundHandlerAdapter {


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf msg1 = (ByteBuf) msg;
        log.info("服务端信息:" + msg1.toString(CharsetUtil.UTF_8));
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        // 连接上 就给服务端发送数据
        ctx.writeAndFlush(Unpooled.copiedBuffer("Hello Server", CharsetUtil.UTF_8));
        SocketAddress socketAddress = ctx.channel().remoteAddress();
        log.info(socketAddress + " 已连接");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info(ctx.channel().remoteAddress() + " 已断开连接");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        ctx.close();
    }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
       在Java界,Netty无疑是开发网络应用的拿手菜。你不需要太多关注复杂的NIO模型和底层网络的细节,使用其丰富的接口,可以很容易的实现复杂的通讯功能。 本课程准备的十二个实例,按照由简单到复杂的学习路线,让你能够快速学习如何利用Netty来开发网络通信应用。                每个实例简洁、清爽、实用,重点在“用”上,即培训大家如何熟练的使用Netty解决实际问题,抛弃以往边讲应用边分析源码的培训模式所带来的“高不成低不就”情况,在已经能够熟练使用、并且清楚开发流程的基础上再去分析源码就会思路清晰、事半功倍。        本套课程的十二个实例,各自独立,同时又层层递进,每个实例都是针对典型的实际应用场景,学了马上就能应用到实际项目中去。 学习好Netty 总有一个理由给你惊喜!! 一、应用场景        Netty已经众多领域得到大规模应用,这些领域包括:物联网领域、互联网领域、电信领域、大数据领域、游戏行业、企业应用、银行证券金融领域、。。。  二、技术深度        多款开源框架中应用了Netty,如阿里分布式服务框架 Dubbo 的 RPC 框架、淘宝的消息中间件 R0cketMQ、Hadoop 的高性能通信和序列化组件 Avro 的 RPC 框架、开源集群运算框架 Spark、分布式计算框架 Storm、并发应用和分布式应用 Akka、。。。  三、就业前景         很多大厂在招聘高级/资深Java工程师时要求熟练学习、或熟悉Netty,下面只是简要列出,这个名单可以很长。。。
### 回答1: 下面是使用 Netty 实现 WebSocket 图片传输的示例代码。需要注意的是,这个示例代码只是提供一个思路,具体的实现细节可能会有所不同。 首先,在服务端,你需要创建一个 ChannelInboundHandler 来处理来自客户端的 WebSocket 消息。在这个 handler 中,你可以检查消息的类型,如果是二进制消息,就读取它并将图片解码为 BufferedImage 对象。然后,你可以将图片存储在服务端或者将它转发给其他客户端。 ``` public class ImageHandler extends SimpleChannelInboundHandler<BinaryWebSocketFrame> { @Override protected void channelRead0(ChannelHandlerContext ctx, BinaryWebSocketFrame frame) throws Exception { // 读取二进制消息并解码为图片 BufferedImage image = ImageIO.read(new ByteArrayInputStream(frame.content().array())); // 处理图片,例如存储或转发 ... } } ``` 然后,在客户端,你需要创建一个 ChannelOutboundHandler 来处理要发送给服务端的 WebSocket 消息。在这个 handler 中,你可以将图片编码为二进制数据并发送给服务端。 ``` public class ImageSender extends ChannelOutboundHandlerAdapter { public void sendImage(ChannelHandlerContext ctx, BufferedImage image) { // 将图片编码为二进制数据 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(image, "png", baos); byte[] data = baos.toByteArray(); // 发送二进制消息 ctx.writeAndFlush(new BinaryWebSocketFrame(Unpooled.wrappedBuffer ### 回答2: 以下是一个使用Netty进行WebSocket传输图片的示例代码服务器代码: ``` 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; 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.stream.ChunkedWriteHandler; public class WebSocketServer { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast(new HttpServerCodec()) .addLast(new HttpObjectAggregator(65536)) .addLast(new ChunkedWriteHandler()) .addLast(new WebSocketServerProtocolHandler("/websocket")) .addLast(new ImageWebSocketServerHandler()); } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture future = bootstrap.bind(8080).sync(); future.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } } ``` 服务器端使用了Netty的WebSocket协议处理器`WebSocketServerProtocolHandler`来支持WebSocket连接,并且根据自定义的图片处理器`ImageWebSocketServerHandler`处理接收到的图片数据。 客户端代码: ``` import io.netty.bootstrap.Bootstrap; 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.NioSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler; public class WebSocketClient { public static void main(String[] args) throws Exception { EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { ch.pipeline() .addLast(new HttpResponseDecoder()) .addLast(new HttpRequestEncoder()) .addLast(new HttpObjectAggregator(65536)) .addLast(new WebSocketClientProtocolHandler("/websocket")) .addLast(new ImageWebSocketClientHandler()); } }) .option(ChannelOption.SO_KEEPALIVE, true); ChannelFuture future = bootstrap.connect("localhost", 8080).sync(); future.channel().closeFuture().sync(); } finally { group.shutdownGracefully(); } } } ``` 客户端代码中,同样使用了Netty的WebSocket协议处理器`WebSocketClientProtocolHandler`来支持WebSocket连接,并且根据自定义的图片处理器`ImageWebSocketClientHandler`处理接收到的图片数据。 通过服务器端和客户端的组合使用,可以实现基于Netty的WebSocket传输图片的功能。 ### 回答3: Netty是一种基于Java的网络编程框架,它提供了一种简单而高效的方式来实现网络通信。WebSocket是一种在Web应用程序中实现双向通信的协议。使用Netty实现WebSocket传输图片的示例代码如下: 1.首先,需要添加Netty和WebSocket的依赖到项目中: ```xml <dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.63.Final</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-transport-native-epoll</artifactId> <version>4.1.63.Final</version> <classifier>linux-x86_64</classifier> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-codec-http</artifactId> <version>4.1.63.Final</version> </dependency> <dependency> <groupId>io.netty</groupId> <artifactId>netty-handler</artifactId> <version>4.1.63.Final</version> </dependency> ``` 2.创建一个WebSocket服务器类,用于处理WebSocket请求: ```java import io.netty.bootstrap.ServerBootstrap; 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.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.stream.ChunkedWriteHandler; import io.netty.handler.stream.ChunkedNioFile; import io.netty.handler.stream.ChunkedWriteHandler; public class WebSocketServer { public void run(int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer() { @Override protected void initChannel(Channel ch) throws Exception { ch.pipeline().addLast("http-codec", new HttpServerCodec()); ch.pipeline().addLast("aggregator", new HttpObjectAggregator(65536)); ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler()); ch.pipeline().addLast("handler", new WebSocketServerHandler()); } }); ChannelFuture future = bootstrap.bind(port).sync(); System.out.println("WebSocket server started on port " + port); future.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new WebSocketServer().run(8080); } } ``` 3.创建一个WebSocket处理器,用于处理WebSocket请求并传输图片: ```java import io.netty.bootstrap.Bootstrap; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.SimpleChannelInboundHandler; 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.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpVersion; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; public class WebSocketServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> { private WebSocketServerHandshaker handshaker; @Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception { if (!msg.decoderResult().isSuccess()) { sendHttpResponse(ctx, msg, HttpResponseStatus.BAD_REQUEST); return; } if ("/ws".equals(msg.uri())) { WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:8080/ws", null, false); handshaker = wsFactory.newHandshaker(msg); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } } else { // 处理静态资源请求 // ... } } private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, HttpResponseStatus status) { ByteBuf content = Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8); FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, content); response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8"); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); ctx.close(); } } ``` 这段代码创建了一个基于Netty的WebSocket服务器,实现了WebSocket请求处理和图片传输的功能。具体步骤如下: 1.创建一个WebSocket服务器类,使用Netty的`ServerBootstrap`配置服务器,并在`initChannel`方法中添加必要的处理器。 2.在WebSocket服务器类中创建一个`WebSocketServerHandler`类,继承自Netty的`SimpleChannelInboundHandler<FullHttpRequest>`,用于处理WebSocket请求。 3.在`channelRead0`方法中,判断传入的请求是否为WebSocket握手请求,并进行相应处理。 4.如果是WebSocket握手请求,则通过`WebSocketServerHandshakerFactory`创建一个握手器,并进行握手。 5.如果不是WebSocket握手请求,则根据需要处理静态资源请求等。 6.在`sendHttpResponse`方法中,通过`FullHttpResponse`返回相关响应信息。 7.最后,在`main`方法中创建一个新的`WebSocketServer`对象并运行。 以上是一个简单Netty WebSocket传输图片的示例代码,用于实现图片的传输和处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值