Java网络编程(9) - Netty怎么做数据通信?Netty的心跳检测怎么实现?Netty怎么用Http协议通信?

Netty实际案例的考虑 – 数据通信实现

      1、长链接:使用长链接通道不断开的形式进行通信,也就是Server和Client的通道一直处于开启状态,如果服务器性能足够好,并且我们的客户端数据也比较少的情况下,可以使用这种。

      2、一次性批量提交数据:这是采用短链接方式,也就是会把数据保存在本地临时缓冲区或者临时表里,当达到临界值时,进行一次性批量提交,又或者根据定时任务轮询提交,这种情况的弊端是做不到实时性传输,在对实时性不高的应用程序可以使用这种。

      3、特殊的长链接:在指定的某一时间内,服务器与某些客户端没有任何通信,则断开连接。下次连接则客户端向服务端发送数据的时候,再次建立连接,但这种需要考虑两个因素。

一是在超时时,服务端和客户端没有任何通信后关闭通道?关闭通道后又如何再次建立连接?

      二是客户端宕机时,无需考虑,下次客户端重启之后就可以与服务器建立连接,但是服务器宕机时,客户端如何与服务器进行链接?

import org.jboss.marshalling.MarshallerFactory;

import org.jboss.marshalling.Marshalling;

import org.jboss.marshalling.MarshallingConfiguration;

 

import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;

import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;

import io.netty.handler.codec.marshalling.MarshallerProvider;

import io.netty.handler.codec.marshalling.MarshallingDecoder;

import io.netty.handler.codec.marshalling.MarshallingEncoder;

 

/**

 * 序列化编解码器:

 * JBossMarshalling

 * GoogleProtobuf

 * 基于ProtobufKyro

 * MessagePack框架

 */

public class N06MarshallingDecoderEncoderUtils {

 

    public final static String TAG = "serial";

   

    /**

     * 解码器:将二进制序列化为java对象

     */

    public static MarshallingDecoder buildDecoder() {

         //通过Marshalling工具类获取到实例对象,serial标识创建的是java的序列化工厂对象

         MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory(TAG);

        

         //创建MarshallingConfiguration对象,并配置版本号

         MarshallingConfiguration marshallingConfiguration = new MarshallingConfiguration();

         marshallingConfiguration.setVersion(5);

        

         //创建Provider

         DefaultUnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, marshallingConfiguration);

        

         //构建Netty的解码对象,并配置provider和单个消息序列化的最大长度

        return new MarshallingDecoder(provider, 1024 * 1024);

    }

   

    /**

     * 编码器:将对象序列化为二进制数组

     */

    public static MarshallingEncoder buildEncoder() {

         //序列化java工厂类

         MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory(TAG);

        

         //创建配置类

         MarshallingConfiguration marshallingConfiguration = new MarshallingConfiguration();

         marshallingConfiguration.setVersion(5);

        

         //创建供应者

         MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, marshallingConfiguration);

        

         //构建NettyMarshallingEncoder对象

         MarshallingEncoder marshallingEncoder = new MarshallingEncoder(provider);

         return marshallingEncoder;

    }

}

import java.io.Serializable;

 

/**

 * 请求数据

 */

public class N06Request implements Serializable {

 

    private static final long serialVersionUID = -7633763905125419996L;

 

    private String data;

 

    public String getData() {

         return data;

    }

 

    public void setData(String data) {

         this.data = data;

    }

 

import java.io.Serializable;

 

/**

 * 响应数据

 */

public class N06Response implements Serializable {

 

    private static final long serialVersionUID = -6704864849770619898L;

 

    private String data;

 

    public String getData() {

         return data;

    }

 

    public void setData(String data) {

         this.data = data;

    }

}

 

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelFutureListener;

import io.netty.channel.ChannelHandlerAdapter;

import io.netty.channel.ChannelHandlerContext;

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.logging.LogLevel;

import io.netty.handler.logging.LoggingHandler;

import io.netty.handler.timeout.ReadTimeoutHandler;

 

/**

 * 案例:数据通信服务端

 */

public class N06DataCommunicationServer {

    public static void main(String[] args) throws Exception {

         //连接和传输数据

         EventLoopGroup connectEventLoopGroup = new NioEventLoopGroup();

         EventLoopGroup dataEventLoopGroup = new NioEventLoopGroup();

        

         //启动类

         ServerBootstrap serverBootstrap = new ServerBootstrap();

         serverBootstrap.group(connectEventLoopGroup, dataEventLoopGroup) //绑定

                          .channel(NioServerSocketChannel.class) //模式

                          .option(ChannelOption.SO_BACKLOG, 1024) //TCP缓冲

                          .handler(new LoggingHandler(LogLevel.INFO)) //日志

                          .childHandler(new ChannelInitializer() { //初始化

                               @Override

                               protected void initChannel(SocketChannel ch) throws Exception {

                                   //编解码器

                                   ch.pipeline().addLast(N06MarshallingDecoderEncoderUtils.buildDecoder());

                                   ch.pipeline().addLast(N06MarshallingDecoderEncoderUtils.buildEncoder());

                                  

                                   //读取超时

                                   ch.pipeline().addLast(new ReadTimeoutHandler(5));

                                  

                                   //处理类

                                   ch.pipeline().addLast(new DataCommunicationServerHandler());

                               }

                          });

        

         //通道

         ChannelFuture channelFuture = serverBootstrap.bind(1111).sync();

         channelFuture.channel().closeFuture().sync();

        

         //关闭

         connectEventLoopGroup.shutdownGracefully();

         dataEventLoopGroup.shutdownGracefully();

        

    }

}

class DataCommunicationServerHandler extends ChannelHandlerAdapter {

   

    @Override

    public void channelActive(ChannelHandlerContext ctx) throws Exception {

         System.out.println("Server Active");

    }

   

    @Override

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

         //已经设置了编解码器

         N06Request request = (N06Request) msg;

         System.out.println("Server" + request.getData());

        

         //响应

         N06Response response = new N06Response();

         response.setData("Hi Client!");

         ctx.writeAndFlush(response)

             //模拟关闭链接,客户端重新链接

             .addListener(ChannelFutureListener.CLOSE);

    }

   

    @Override

    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

         System.out.println("Server Read Complete");

    }

   

    @Override

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

         cause.printStackTrace();

    }

}

import io.netty.bootstrap.Bootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelHandlerAdapter;

import io.netty.channel.ChannelHandlerContext;

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;

import io.netty.handler.logging.LogLevel;

import io.netty.handler.logging.LoggingHandler;

import io.netty.handler.timeout.ReadTimeoutHandler;

import io.netty.util.ReferenceCountUtil;

 

/**

 * 案例:数据通信客户端

 */

public class N06DataCommunicationClient {

    public static void main(String[] args) throws InterruptedException {

         //创建链接

         DataCommunicationClient dataCommunicationClient = new DataCommunicationClient();

         ChannelFuture channelFuture = dataCommunicationClient.getChannelFuture();

        

         //写出数据

         N06Request request = new N06Request();

         request.setData("HiServer!");

         channelFuture.channel().writeAndFlush(request);

        

         channelFuture.channel().closeFuture().sync();

        

        

         //在服务端开启,写完数据就断开,模拟重连的过程

         //获取连接

         ChannelFuture channelFuture2 =     dataCommunicationClient.getChannelFuture();

         System.out.println(channelFuture2.channel().isActive());

         System.out.println(channelFuture2.channel().isOpen());

        

         //再次发送数据

         request = new N06Request();

         request.setData("HiServer2222222!");

         channelFuture2.channel().writeAndFlush(request);

         channelFuture2.channel().closeFuture().sync();

        

         System.out.println("结束");

    }

}

class DataCommunicationClient {

   

    private EventLoopGroup eventLoopGroup;

    private Bootstrap bootstrap;

    private ChannelFuture channelFuture;

   

    /**

     * 创建实例时,就初始化启动类

     */

    public DataCommunicationClient () {

         //创建链接

         this.eventLoopGroup = new NioEventLoopGroup();

        

         //启动类

         this.bootstrap = new Bootstrap();

         this.bootstrap.group(eventLoopGroup) //绑定

                          .channel(NioSocketChannel.class) //模式

                          .handler(new LoggingHandler(LogLevel.INFO)) //日志

                          .handler(new ChannelInitializer() {

                               @Override

                               protected void initChannel(SocketChannel ch) throws Exception {

                                   //编解码器

                                   ch.pipeline().addLast(N06MarshallingDecoderEncoderUtils.buildDecoder());

                                   ch.pipeline().addLast(N06MarshallingDecoderEncoderUtils.buildEncoder());

                                  

                                   //超时

                                   ch.pipeline().addLast(new ReadTimeoutHandler(5));

                                  

                                   //数据处理类

                                   ch.pipeline().addLast(new DataCommunicationClientHandler());

                               }

                          });

    }

   

    /**

     * 建立链接

     */

    public void connect() {

         try {

             this.channelFuture = bootstrap.connect("127.0.0.1", 1111).sync();

             System.out.println("链接建立成功!");

         } catch (InterruptedException e) {

             e.printStackTrace();

         }

    }

   

    /**

     * 获取连接

     */

    public ChannelFuture getChannelFuture() {

         //为空就继续获取连接

         if(null == this.channelFuture) {

             this.connect();

         }

         //继续获取连接

         if (!this.channelFuture.channel().isActive()) {

             this.connect();

         }

         return channelFuture;

    }

}

class DataCommunicationClientHandler extends ChannelHandlerAdapter {

   

    @Override

    public void channelActive(ChannelHandlerContext ctx) throws Exception {

         System.out.println("Client Active");

    }

   

    @Override

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

         try {

             N06Response response = (N06Response) msg;

             System.out.println("Client" + response);

         } finally {

             ReferenceCountUtil.release(msg);

         }

    }

   

    @Override

    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {

         System.out.println("Client Read Complete");

    }

   

    @Override

    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

         cause.printStackTrace();

    }

}

 

Netty实际案例– 心跳检测实现

      使用Socket通信一般会处理多个服务器之间的心跳检测,一般来讲去维护一个服务器集群,肯定要有一台或几台服务器的Master,然后由多态Slave,那么Master肯定时时刻刻知道自己下面的Slave服务器的各种情况,然后进行实时监控的功能,在分布式框架里叫作心跳检测或心跳监控,最佳处理方案就是使用一些通信框架去实现。

import org.jboss.marshalling.MarshallerFactory;

import org.jboss.marshalling.Marshalling;

import org.jboss.marshalling.MarshallingConfiguration;

 

import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;

import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;

import io.netty.handler.codec.marshalling.MarshallerProvider;

import io.netty.handler.codec.marshalling.MarshallingDecoder;

import io.netty.handler.codec.marshalling.MarshallingEncoder;

 

/**

 * 序列化编解码器:

 * JBossMarshalling

 * GoogleProtobuf

 * 基于ProtobufKyro

 * MessagePack框架

 */

public class N07MarshallingDecoderEncoderUtils {

 

    public final static String TAG = "serial";

   

    /**

     * 解码器:将二进制序列化为java对象

     */

    public static MarshallingDecoder buildDecoder() {

         //通过Marshalling工具类获取到实例对象,serial标识创建的是java的序列化工厂对象

         MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory(TAG);

        

         //创建MarshallingConfiguration对象,并配置版本号

         MarshallingConfiguration marshallingConfiguration = new MarshallingConfiguration();

         marshallingConfiguration.setVersion(5);

        

         //创建Provider

         DefaultUnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, marshallingConfiguration);

        

         //构建Netty的解码对象,并配置provider和单个消息序列化的最大长度

         return new MarshallingDecoder(provider, 1024 * 1024);

    }

   

    /**

     * 编码器:将对象序列化为二进制数组

     */

    public static MarshallingEncoder buildEncoder() {

         //序列化java工厂类

         MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory(TAG);

        

         //创建配置类

         MarshallingConfiguration marshallingConfiguration = new MarshallingConfiguration();

         marshallingConfiguration.setVersion(5);

        

         //创建供应者

         MarshallerProvider provider = new DefaultMarshallerProvider(marshallerFactory, marshallingConfiguration);

        

         //构建NettyMarshallingEncoder对象

         MarshallingEncoder marshallingEncoder = new MarshallingEncoder(provider);

         return marshallingEncoder;

    }

}

import java.io.Serializable;

 

/**

 * 请求数据

 */

public class N07Request implements Serializable {

 

    private static final long serialVersionUID = -7633763905125419996L;

 

    private String data;

 

    public String getData() {

         return data;

    }

 

    public void setData(String data) {

         this.data = data;

    }

}

import java.io.Serializable;

 

/**

 * 响应数据

 */

public class N07Response implements Serializable {

 

    private static final long serialVersionUID = -6704864849770619898L;

 

    private String data;

 

    public String getData() {

         return data;

    }

 

    public void setData(String data) {

         this.data = data;

    }

 

    @Override

    public String toString() {

         return "Response [data=" + data + "]";

    }

}

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelHandlerAdapter;

import io.netty.channel.ChannelHandlerContext;

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.logging.LogLevel;

import io.netty.handler.logging.LoggingHandler;

 

/**

 * 案例:心跳检测服务端

 */

public class N07HeartbeatServer {

    public static void main(String[] args) throws Exception {

         //链接和传数据

         EventLoopGroup connectEventLoopGroup = new NioEventLoopGroup();

         EventLoopGroup dataEventLoopGroup = new NioEventLoopGroup();

        

         //启动类

         ServerBootstrap serverBootstrap = new ServerBootstrap();

         serverBootstrap.group(connectEventLoopGroup, dataEventLoopGroup) //绑定

                          .channel(NioServerSocketChannel.class) //模式

                          .option(ChannelOption.SO_BACKLOG, 1024) //TCP缓冲区

                          .handler(new LoggingHandler(LogLevel.INFO)) //日志

                           .childHandler(new ChannelInitializer() {

                               @Override

                               protected void initChannel(SocketChannel ch) throws Exception {

                                   //编解码器

                                   ch.pipeline().addLast(N07MarshallingDecoderEncoderUtils.buildDecoder());

                                   ch.pipeline().addLast(N07MarshallingDecoderEncoderUtils.buildEncoder());

                                  

                                   //处理类

                                   ch.pipeline().addLast(new HeartbeatServerHandler());

                               }

                          });

 

         System.out.println("服务端启动......");

        

         //绑定端口

         ChannelFuture channelFuture = serverBootstrap.bind(1111).sync();

         channelFuture.channel().closeFuture().sync();

        

         //关闭

         connectEventLoopGroup.shutdownGracefully();

         dataEventLoopGroup.shutdownGracefully();

    }

}

class HeartbeatServerHandler extends ChannelHandlerAdapter {

   

    private static final String KEY = "111111122222233333333";

   

    /**

     * 认证

     */

    private boolean auth(ChannelHandlerContext ctx, Object msg) throws Exception {

         System.out.println("进入数据验证.......");

         String data = (String)msg;

         if (KEY.equals(data)) {

             ctx.writeAndFlush("success");

             return true;

         }

         ctx.writeAndFlush("failure");

//       ctx.writeAndFlush("failure").addListener(ChannelFutureListener.CLOSE);

         return true;

    }

   

    @Override

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

         //认证

         if (msg instanceof String) {

             boolean auth = auth(ctx, msg);

             System.out.println("验证结果:" + auth);

         //心跳数据

         } else if(msg instanceof N07Request) {

             N07Request request = (N07Request) msg;

             System.out.println("Server" + request.getData());

             ctx.writeAndFlush("收到状态数据");

//           ctx.writeAndFlush("收到状态数据").addListener(ChannelFutureListener.CLOSE);

        

         }else {

             ctx.writeAndFlush("failure");

//           ctx.writeAndFlush("failure").addListener(ChannelFutureListener.CLOSE);

         }

    }

}

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

 

import io.netty.bootstrap.Bootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelHandlerAdapter;

import io.netty.channel.ChannelHandlerContext;

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;

import io.netty.util.ReferenceCountUtil;

 

/**

 * 案例:心跳检测客户端

 */

public class N07HeartbeatClient {

    public static void main(String[] args) throws Exception {

         //创建链接

         EventLoopGroup eventLoopGroup = new NioEventLoopGroup();

        

         //启动

         Bootstrap bootstrap = new Bootstrap();

         bootstrap.group(eventLoopGroup) //绑定

                      .channel(NioSocketChannel.class) //模式

                      .handler(new ChannelInitializer() { //初始化

                          @Override

                          protected void initChannel(SocketChannel ch) throws Exception {

                               //编解码器

                              ch.pipeline().addLast(N07MarshallingDecoderEncoderUtils.buildDecoder());

                              ch.pipeline().addLast(N07MarshallingDecoderEncoderUtils.buildEncoder());

                              

                               //处理器

                               ch.pipeline().addLast(new HeartbeatClientHandler());

                          }

                      });

        

         //链接

         ChannelFuture channelFuture = bootstrap.connect("127.0.0.1",1111).sync();

         channelFuture.channel().closeFuture().sync();

        

         //关闭

         eventLoopGroup.shutdownGracefully();

    }

}

class HeartbeatClientHandler extends ChannelHandlerAdapter {

   

    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

   

    private static final String KEY = "111111122222233333333";

   

    @Override

    public void channelActive(ChannelHandlerContext ctx) throws Exception {

         System.out.println("客户端启动去验证...");

         //通道启用时,就去链接

         ctx.writeAndFlush(KEY);

    }

   

    @Override

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

         try {

             System.out.println("客户端读取回传的数据...");

             if (msg instanceof String) {

                  //认证成功,发送心跳数据

                  if("success".equals(msg)) {

                      //延迟2秒发送,测试时,要注意,Server端设置了关闭(ChannelFutureListener.CLOSE

                      this.scheduledExecutorService.scheduleWithFixedDelay(new HeartbeatRun(ctx), 0, 2, TimeUnit.SECONDS);

                  }

                  System.out.println("Client" + msg);

             }else {

                  System.out.println("ClientOther - " + msg);

             }

            

         } finally {

             ReferenceCountUtil.release(msg);

         }

    }

}

class HeartbeatRun implements Runnable {

   

    private ChannelHandlerContext ctx;

   

    public HeartbeatRun(ChannelHandlerContext ctx) {

         super();

         this.ctx = ctx;

    }

 

    @Override

    public void run() {

         //发送机器数据

//       Sigar sigar = new Sigar();

         try {

//           CpuPerc cpuPerc = sigar.getCpuPerc();

             N07Request request = new N07Request();

//           request.setData("Cpu使用率:" + cpuPerc.getUser());

             request.setData("Cpu使用率:88%");

             ctx.writeAndFlush(request);

         } catch (Exception e) {

             e.printStackTrace();

         }

    }

}

 

Netty使用Http协议通信案例,并实现文件服务器案例

      Http协议是超文本协议,是建立在TCP传输协议之上的应用层协议,目前主流是针对WEB开发,Http的应用非常广泛。其中Netty的Http协议也是一部非阻塞的。

 

Http特点

      简单:客户端请求服务器只需要携带指定的URL和携带必要的参数即可。

      灵活:Http协议允许传输任意类型的数据对象,传输内容由Http消息头中的Content-Type加以标记。

      无状态:协议对事务处理是没有记录能力的,如果后续处理需要之前的信息,必须重新获取,侧面显示出Http的轻量级、敏捷、负载轻。

      组成部分:请求头、请求行、请求正文。

      请求方式:Get(获取)、Post(附加新的提交数据)、Head(请求获取由请求URI标识的资源的响应消息头)、Put(新增)、Delete(删除)、Trace(测试和诊断)、Connect(保留未来)、Options(查询服务器性能)

      状态码:分类为1、2、3、4、5。

/**

 * 案例 - Netty使用Http协议,也可基于SSL的链接访问

 */

public class N08HttpRequestServer {

 

    //SSL

    static SslContext sslContext = null;

   

    public static void main(String[] args) throws Exception {

        

         //SSL

         boolean ssl = null != System.getProperty("ssl");

        

         //端口配置,SSL的端口不一样

         int port = Integer.parseInt(System.getProperty("port",ssl? "8443" : "8080"));

        

         //SSL配置

         if (ssl) {

             SelfSignedCertificate selfSignedCertificate = new SelfSignedCertificate();

             sslContext = SslContext.newServerContext(selfSignedCertificate.certificate(), selfSignedCertificate.privateKey());

         }

        

         //配置链接和传输数据

         EventLoopGroup connectEventLoopGroup = new NioEventLoopGroup();

         EventLoopGroup dataEventLoopGroup = new NioEventLoopGroup();

        

         //启动类

         ServerBootstrap serverBootstrap = new ServerBootstrap();

         serverBootstrap.group(connectEventLoopGroup,dataEventLoopGroup) //绑定

                          .option(ChannelOption.SO_BACKLOG, 1024)

                          .channel(NioServerSocketChannel.class) //模式

                          .handler(new LoggingHandler(LogLevel.INFO)) //日志

                          .childHandler(new ChannelInitializer() {

                               @Override

                               protected void initChannel(SocketChannel ch) throws Exception {

                                   //SSL配置

                                   if(null != sslContext) {

                                       ch.pipeline().addLast(sslContext.newHandler(ch.alloc()));

                                   }

                                  

                                   //编解码器

                                   ch.pipeline().addLast(new HttpServerCodec());

                                  

                                   //数据处理类

                                   ch.pipeline().addLast(new HttpRequestServerHandler());

                               }

                          });

   

         //启动

         ChannelFuture channelFuture = serverBootstrap.bind(port).sync();

         System.out.println("浏览器访问:http://127.0.0.1:8080/");

         channelFuture.channel().closeFuture().sync();

        

         //关闭

         connectEventLoopGroup.shutdownGracefully();

         dataEventLoopGroup.shutdownGracefully();

    }

}

class HttpRequestServerHandler extends ChannelHandlerAdapter {

   

    /**

     * 响应内容

     */

    private static final byte[] CONTENT = {'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};

   

    @Override

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {

         //请求是Http的请求

         if (msg instanceof HttpRequest) {

             //编解码器已设置

             HttpRequest httpRequest = (HttpRequest) msg;

            

             if(HttpHeaderUtil.is100ContinueExpected(httpRequest)) {

                  ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE));

             }

            

             //响应数据

             DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK,Unpooled.wrappedBuffer(CONTENT));

             response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/plain");

             response.headers().setInt(HttpHeaderNames.CONTENT_LENGTH,response.content().readableBytes());

            

             //是否活跃的响应

             boolean keepAlive = HttpHeaderUtil.isKeepAlive(httpRequest);

             if (!keepAlive) {

                  ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);

            

             }else {

                  response.headers().set(HttpHeaderNames.CONNECTION,HttpHeaderValues.KEEP_ALIVE);

                  ctx.writeAndFlush(response);

             }

         }

    }

}

 

Http文件服务器案例

      Netty的Http协议栈从性能和可靠性都比较优异,非常适合Web容器场景下应用,相比于传统的Tomcat、Jetty等Web容器更加轻量级,灵活性和定制型也更好。

import java.io.File;

import java.io.RandomAccessFile;

 

import javax.activation.MimetypesFileTypeMap;

 

import io.netty.bootstrap.ServerBootstrap;

import io.netty.channel.ChannelFuture;

import io.netty.channel.ChannelFutureListener;

import io.netty.channel.ChannelHandlerContext;

import io.netty.channel.ChannelInitializer;

import io.netty.channel.ChannelProgressiveFuture;

import io.netty.channel.ChannelProgressiveFutureListener;

import io.netty.channel.EventLoopGroup;

import io.netty.channel.SimpleChannelInboundHandler;

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

import io.netty.handler.codec.http.FullHttpRequest;

import io.netty.handler.codec.http.HttpHeaderNames;

import io.netty.handler.codec.http.HttpHeaderUtil;

import io.netty.handler.codec.http.HttpHeaderValues;

import io.netty.handler.codec.http.HttpObjectAggregator;

import io.netty.handler.codec.http.HttpRequestDecoder;

import io.netty.handler.codec.http.HttpResponseEncoder;

import io.netty.handler.codec.http.HttpResponseStatus;

import io.netty.handler.codec.http.HttpVersion;

import io.netty.handler.codec.http.LastHttpContent;

import io.netty.handler.stream.ChunkedFile;

import io.netty.handler.stream.ChunkedWriteHandler;

 

/**

 * 案例 - 文件服务器,Http下载文件,并实时监控

 */

public class N09HttpDownloadFileServer {

    public static void main(String[] args) throws Exception {

        

         String url = "/sources/";

        

         //链接和数据处理

         EventLoopGroup connectEventLoopGroup = new NioEventLoopGroup();

         EventLoopGroup dataEventLoopGroup = new NioEventLoopGroup();

        

         //启动类

         ServerBootstrap serverBootstrap = new ServerBootstrap();

         serverBootstrap.group(connectEventLoopGroup, dataEventLoopGroup) //绑定

                          .channel(NioServerSocketChannel.class) //模式

                          .childHandler(new ChannelInitializer() { //初始化

                               @Override

                               protected void initChannel(SocketChannel ch) throws Exception {

                                   //编解码器,请求解码,响应编码

                                   ch.pipeline().addLast("http-decoder", new HttpRequestDecoder());

                                   ch.pipeline().addLast("http-encoder", new HttpResponseEncoder());

                                  

                                   //多个消息转为单一的FullHttpRequestFullHttpResponse

                                   ch.pipeline().addLast("http-aggregator",new HttpObjectAggregator(65535));

                                  

                                   //支持异步发送码流,用于支持大文件传输,但不占用过多的内存,防止java内存溢出

                                    ch.pipeline().addLast("http-chunked",new ChunkedWriteHandler());

                                  

                                   //自定义文件服务器业务处理

                                   ch.pipeline().addLast("fileServerHandler",new HttpDownloadFileServerHandler(url));

                               }

                          });

        

         //绑定端口

         ChannelFuture channelFuture = serverBootstrap.bind("127.0.0.1",1111).sync();

         System.out.println("访问地址:http://127.0.0.1:1111" + url);

         System.out.println("下载地址:http://127.0.0.1:1111" + url + "2.png");

         channelFuture.channel().closeFuture().sync();

        

         //关闭

         connectEventLoopGroup.shutdownGracefully();

         dataEventLoopGroup.shutdownGracefully();

    }

}

class HttpDownloadFileServerHandler extends SimpleChannelInboundHandler {

   

    //访问地址

    private String url;

   

    public HttpDownloadFileServerHandler(String url) {

         this.url = url;

    }

 

    @Override

    protected void messageReceived(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {

         //获取请求的uri路径

         String uri = msg.uri();

        

         //正常的话,要校验请求、校验uri、校验文件或文件夹等等

        

         //拼接文件地址

         String path = System.getProperty("user.dir") + File.separator + uri;

         System.out.println("请求的路径:" + path);

        

         //随机文件读写类,只读的方式

         RandomAccessFile randomAccessFile = null;

         try {

             randomAccessFile = new RandomAccessFile(new File(path), "r");

         } catch (Exception e) {

             e.printStackTrace();

         }

        

         //响应数据

         DefaultHttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);

         //响应信息

         HttpHeaderUtil.setContentLength(response, randomAccessFile.length());

         //响应头

         response.headers().set(HttpHeaderNames.CONTENT_TYPE,new MimetypesFileTypeMap().getContentType(path));

         //是否一直保持连接

         if (HttpHeaderUtil.isKeepAlive(msg)) {

             response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);

         }

         //写出

         ctx.write(response);

        

         //构建文件发送线程,将文件写入到Chunked缓冲区

         ChannelFuture channelFuture = ctx.write(new ChunkedFile(randomAccessFile,0,randomAccessFile.length(),8192),ctx.newProgressivePromise());

         //监听传输文件

         channelFuture.addListener(new ChannelProgressiveFutureListener() {

             @Override

             public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) throws Exception {

                  if (total < 0) {

                      System.out.println("传输进展:" + progress);

                  }else {

                      System.out.println("传输进展:" + progress + " / " + total);

                  }

             }

             @Override

             public void operationComplete(ChannelProgressiveFuture future) throws Exception {

                  System.out.println("传输结束!");

             }

         });

         //如果使用Chunked编码,需要发送一个编码结束的看空消息体进行标记,表示所有消息体已经成功发送

         ChannelFuture lastChannelFuture = ctx.write(LastHttpContent.EMPTY_LAST_CONTENT);

         //刷出缓存

         ctx.flush();

         if (!HttpHeaderUtil.isKeepAlive(msg)) {

             lastChannelFuture.addListener(ChannelFutureListener.CLOSE);

         }

        

         System.out.println("处理完成");

    }

}

 

你可能感兴趣的:(Java,Netty怎么做数据通信,Netty的心跳检测怎么实现,Netty怎么用Http通信,Netty实现文件服务器,Netty与Http结合)