为什么netty上的文件传输速度非常慢(4.1.5-Final)

时间:2016-10-04 06:21:42

标签: java performance file sockets netty

在我使用Netty 4.1.5-Final的基于套接字的服务器实现中,当我将视频/图像文件转换为块(20K块大小)时,我发现大约350+ ms是两个块之间的差异,不知道如何减少那个。

这是我的主要服务器代码:

public class MultimediaServer extends Thread implements IMultimediaServer, BeanFactoryAware {

/**
 * Logger Instance
 */
protected Logger logger = Logger.getLogger(this.getClass());

@Autowired
private Properties props;

private RequestHandler requestHandler;

private BeanFactory beanFactory;

private int port;

private int maxConnection;


private int timeout = 30000;

private EventLoopGroup bossGroup = null;
private EventLoopGroup workerGroup = null;

@Override
public void run() {
    try {
        bossGroup = new NioEventLoopGroup();
        workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, Const.PACKET_HEADER_LENGTH, 0, Const.PACKET_HEADER_LENGTH));
                            ch.pipeline().addLast("messageDecoder", new MessageDecoder());
                            ch.pipeline().addLast("frameEncoder", new ResponseHandler(Const.PACKET_HEADER_LENGTH));
                            ch.pipeline().addLast("bytesEncoder", new ByteArrayEncoder());

                            ch.pipeline().addLast(getHandler());
                        }
                    }).option(ChannelOption.SO_BACKLOG, maxConnection)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.SO_REUSEADDR, true)
                    .option(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout)
                    .option(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024)
                    .option(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 128 * 1024)
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)

                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childOption(ChannelOption.SO_REUSEADDR, true)
                    .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout)
                    .childOption(ChannelOption.MAX_MESSAGES_PER_READ, Integer.MAX_VALUE)
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    .childOption(ChannelOption.WRITE_BUFFER_LOW_WATER_MARK, 32 * 1024)
                    .childOption(ChannelOption.WRITE_BUFFER_HIGH_WATER_MARK, 128 * 1024);


            // Bind and start to accept incoming connections.
            ChannelFuture f = serverBootstrap.bind(this.port).sync();

            // Wait until the server socket is closed.
            // In this example, this does not happen, but you can do that to
            // gracefully shut down your server.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    } catch (Throwable e) {
        logger.error("ERROR : While starting the Konvx service ", e);
    }
}

@Override
public void startServer(int port) {
    super.setName("KonvxMultimediaServer : " + port);
    this.port = port;
    this.start();
}

@Override
public void stopServer() {
    workerGroup.shutdownGracefully();
    bossGroup.shutdownGracefully();
}

public RequestHandler getRequestHandler() {
    return requestHandler;
}

public void setRequestHandler(RequestHandler requestHandler) {
    this.requestHandler = requestHandler;
}

/**
 * Return Request Handler
 * @return RequestHandler
 */
private RequestHandler getHandler() {
    return (RequestHandler) beanFactory.getBean("requestHandler", RequestHandler.class);
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    this.beanFactory = beanFactory;
}

@Value("${konvx.maxConnection}")
public void setMaxConnection(String maxConnection) {
    this.maxConnection = Integer.parseInt(maxConnection);
}

@Value("${konvx.socket.timeout}")
public void setTimeout(String timeout) {
    this.timeout = Integer.parseInt(timeout);
}
}

这是频道处理程序

public class RequestHandler extends SimpleChannelInboundHandler<KonvxMessage> {

/**
 * Logger Instance
 */
private Logger logger = Logger.getLogger(this.getClass());

@Autowired
private Router router;

@Autowired
protected UserPool userPool;

@Override
public void channelRead0(ChannelHandlerContext ctx, KonvxMessage message) throws Exception {
    Packet packet = new Packet();
    packet.setCtx(ctx);
    try {
        if (message == null) {
            logger.warn("Warning - message is empty");
            return;
        }

        // Throw the exception if in-bound message does not magic cookie
        if (!message.hasCookie()) {
            logger.error("ERROR: Bad Cookie :" + message);
            return;
        }

        // Checking if user is a valid/registered to our application
        if (!userPool.isValidUser(message.getUserId())) {
            packet.writeMessage(KonvxMessageFactory.getInvalidUserMessage(message));
            return;
        }

        packet.setInMessage(message);
        router.route(packet);
    } catch (Exception e) {
        logger.error("ERROR : Whie receiving/processing the in-bound message ", e);
        packet.writeMessage(KonvxMessageFactory.getErrorMessage(message, KonvxError.UNKNOWN_ERROR));
    }
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    ctx.flush();
}

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    logger.warn("WARN : Connection problem - " + cause.getMessage() + " Client address :" + ctx.channel().remoteAddress());
    ctx.close();
    return;
}
}

这是数据包的解码器 -

public class MessageDecoder extends ByteToMessageDecoder {

/**
 * Logger Instance
 */
protected Logger logger = Logger.getLogger(this.getClass());

@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    // Parsing the object
    String msg = null;
    try {
        byte[] bytes = new byte[in.readableBytes()];
        if (bytes.length <= 0) {
            logger.debug("Total readable bytes :" + in.readableBytes() + " exiting...");
            return;
        }

        in.readBytes(bytes);

        msg = new String(bytes, CharsetUtil.UTF_8);
        // Return if message is empty
        if (msg.isEmpty()) {
            logger.warn("Message is empty...exiting...");
            return;
        }

        KonvxMessage konvxMessage = JsonUtil.parseMessage(msg);

        // Logging the incoming message
        StringBuilder logMessage = new StringBuilder();
        logMessage.append("Incoming message :").append(System.lineSeparator())
        .append(konvxMessage)
        .append(System.lineSeparator());

        logger.info(logMessage.toString());

        out.add(konvxMessage);
    } catch (Throwable e) {
        logger.error("ERROR : While receiving/parsing/decoding the message " + msg, e);

        new Packet(ctx).writeMessage(KonvxMessageFactory.getParseFailedErrorMessage(msg));
    } 
}
}

请帮忙,如何微调netty以提高移动设备和我的java服务器之间套接字的文件传输性能。

0 个答案:

没有答案