2014-12-08 4 views
2

서버에서 요청한 클라이언트 인 파일을 서버에서 클라이언트로 보내려고합니다. 클라이언트가 FileRequestProtocol의 파일을 선택하여 서버로 전송하면 서버는 파일 크기를 FileRequestProtocol 파일에 추가하고이를 클라이언트에 반환합니다.Netty.io를 사용하여 서버에서 클라이언트로 파일 보내기

클라이언트가 파이프 라인에 올바른 파일 크기의 새로운 FileChunkReqWriteHandler을 추가합니다.

서버가 컨텍스트와 원하는 파일로 새 ChunkedFileServerHandler을 만들고 보내려고 시도하지만 FileChunkReqWriteHandler은 채널에서 바이트를 읽지 않습니다.

내가 뭘 잘못하고 있니?

로그인

INFO ProtocolHeadHandler:48 - Client send ProtocolHead [version=1, jobType=FILEREQUEST] 
INFO ProtocolHeadServerHandler:36 - Server receive ProtocolHead [version=1, jobType=FILEREQUEST] 
INFO ProtocolHeadHandler:57 - Client ProtocolHead equals, Send Protocol FileRequestProtocol [filePath=test.jpg, fileSize=0] 
INFO FileRequestServerHandler:42 - Server new FileRequest FileRequestProtocol [filePath=test.jpg, fileSize=0] 
INFO FileRequestHandler:41 - Client receives FileRequestProtocol [filePath=test.jpg, fileSize=174878] 
INFO ChunkedFileServerHandler:39 - New ChunkedFileServerHandler 
INFO FileChunkReqWriteHandler:20 - New ChunkedFile Handler FileRequestProtocol [filePath=test.jpg, fileSize=174878] 

클라이언트

FileRequestHandler.java

public class FileRequestHandler extends 
    SimpleChannelInboundHandler<FileRequestProtocol> { 

private Logger logger = Logger.getLogger(this.getClass()); 

public FileRequestHandler() { 
} 

@Override 
public void channelRead0(ChannelHandlerContext ctx, FileRequestProtocol msg) { 
    logger.info("Client receives " + msg); 
    ReferenceCountUtil.release(msg); 
    ctx.channel().pipeline().addLast(new FileChunkReqWriteHandler(msg)); 
} 

@Override 
public void channelReadComplete(ChannelHandlerContext ctx) { 
    logger.info("Client read complete"); 
    ctx.flush(); 
} 

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

FileChunkReqWriteHandler.java

public class FileChunkReqWriteHandler extends SimpleChannelInboundHandler<ChunkedFile> { 

FileRequestProtocol fileRequestProtocol; 
private Logger logger = Logger.getLogger(this.getClass()); 


public FileChunkReqWriteHandler(FileRequestProtocol msg) { 
    this.fileRequestProtocol = msg; 
    logger.info("New ChunkedFile Handler " + msg); 
} 

@Override 
public void channelActive(ChannelHandlerContext ctx) { 
    logger.info("in channel active method"); 
} 

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

    if (ctx.channel().isActive()) { 
     ctx.writeAndFlush("ERR: " + 
       cause.getClass().getSimpleName() + ": " + 
       cause.getMessage() + '\n').addListener(ChannelFutureListener.CLOSE); 
    } 
} 

@Override 
protected void channelRead0(ChannelHandlerContext ctx, ChunkedFile msg) 
     throws Exception { 
    logger.info("in channelRead0"); 

} 

@Override 
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
    logger.info("channelRead"); 
    ByteBuf buf = (ByteBuf) msg; 
    byte[] bytes = new byte[buf.readableBytes()]; 
    buf.readBytes(bytes); 
    if(buf.readableBytes() >= this.fileRequestProtocol.getFileSize()) 
    { 
     logger.info("received all data"); 
    } 
} 
} 

서버

FileRequestServerHandler.java

public class FileRequestServerHandler extends 
    SimpleChannelInboundHandler<FileRequestProtocol> { 

private File f; 
private Logger logger = Logger.getLogger(this.getClass()); 

@Override 
public void channelRead0(ChannelHandlerContext ctx, FileRequestProtocol fileRequest) { 
    logger.info("Server new FileRequest " + fileRequest); 
    f = new File(fileRequest.getFilePath()); 
    fileRequest.setFileSize(f.length()); 
    ctx.writeAndFlush(fileRequest); 

    new ChunkedFileServerHandler(ctx,f); 
} 

@Override 
public void channelReadComplete(ChannelHandlerContext ctx) { 
    logger.info("Server read complete"); 

} 

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

ChunkedFileServerHandler.java

public class ChunkedFileServerHandler extends ChunkedWriteHandler { 

private Logger logger = Logger.getLogger(this.getClass()); 

private File file; 
public ChunkedFileServerHandler(ChannelHandlerContext ctx, File file) { 
    this.file = file; 

    logger.info("New ChunkedFileServerHandler"); 
    ChunkedFile chunkedFile; 
    try { 
     chunkedFile = new ChunkedFile(this.file); 
     ctx.writeAndFlush(chunkedFile); 
     ctx.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 


@Override 
public void channelActive(ChannelHandlerContext ctx) throws Exception { 
    super.channelActive(ctx); 
    logger.info("FILE WRITE GETS ACTIVE"); 
} 

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

업데이트

public class ServerInitializer extends ChannelInitializer<SocketChannel> { 

@Override 
protected void initChannel(SocketChannel ch) throws Exception { 
    ChannelPipeline p = ch.pipeline(); 

    p.addLast("encoder", new ObjectEncoder()); 
    p.addLast("decoder", 
      new ObjectDecoder(ClassResolvers.cacheDisabled(null))); 
    p.addLast("protocolhead", new ProtocolHeadServerHandler()); 
    p.addLast("filerequestserverhandler", new FileRequestServerHandler()); 
    p.addLast("chunkedfileserver", new ChunkedFileServerHandler()); 

} 

} 

서버 시작

public void startUp() 
{ 
     bossGroup = new NioEventLoopGroup(1); 
     workerGroup = new NioEventLoopGroup(); 
     try { 
      ServerBootstrap b = new ServerBootstrap(); 
      b.group(bossGroup, workerGroup) 
      .channel(NioServerSocketChannel.class) 
      .handler(new LoggingHandler(LogLevel.INFO)) 
      .childHandler(new ServerInitializer()); 

      // Bind and start to accept incoming connections. 
      b.bind(this.port).sync().channel().closeFuture().sync(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } finally { 
      bossGroup.shutdownGracefully(); 
      workerGroup.shutdownGracefully(); 
     } 
} 
+0

파이프 라인 구성을 표시 할 수 있습니까? 예를 들어 서버 측의 파이프 라인에 ChunkWriteHandler가 있습니까? –

+0

나는이 질문에 대한 업데이트를 만들었습니다. "ChunkedFileServerHandler"가 파이프 라인에 있습니다. – jussi

답변

1

이 개 부분은 내가 볼 수 있습니다 :

1) 당신은 당신의 자신의 핸들러 내에서 새로운 핸들러를 작성하지 않아야하지만, 직접 ChunkedFile을 생성하고 쓰기 :

public class FileRequestServerHandler extends 
    SimpleChannelInboundHandler<FileRequestProtocol> { 

    private File f; 
    private Logger logger = Logger.getLogger(this.getClass()); 

    @Override 
    public void channelRead0(ChannelHandlerContext ctx, FileRequestProtocol fileRequest) { 
     logger.info("Server new FileRequest " + fileRequest); 
     f = new File(fileRequest.getFilePath()); 
     fileRequest.setFileSize(f.length()); 
     ctx.writeAndFlush(fileRequest); 

     // directly make your chunkedFile there instead of creating a sub handler 
     chunkedFile = new ChunkedFile(this.file); 
     ctx.writeAndFlush(chunkedFile);// need a specific handler 
     // Don't create such an handler: new ChunkedFileServerHandler(ctx,f); 
} 

2) ChunkedInput (여기 ChunkedFile)를 사용하여 쓰기 때문에 당신의 이니셜 모양을 수 있도록, 당신은 당신의 파이프 라인 핸들러 전에 ChunkedWriteHandler에 있어야합니다

public class ServerInitializer extends ChannelInitializer<SocketChannel> { 
    @Override 
    protected void initChannel(SocketChannel ch) throws Exception { 
     ChannelPipeline p = ch.pipeline(); 

     p.addLast("encoder", new ObjectEncoder()); 
     p.addLast("decoder", 
      new ObjectDecoder(ClassResolvers.cacheDisabled(null))); 
     p.addLast("chunkedWriteHandler", new ChunkedWriteHandler());// added 
     p.addLast("protocolhead", new ProtocolHeadServerHandler()); 
     p.addLast("filerequestserverhandler", new FileRequestServerHandler()); 
     // removed: p.addLast("chunkedfileserver", new ChunkedFileServerHandler()); 
    } 
} 

ChunkedWriteHandler의 위치는 변경 될 수 있지만 항상 ChunkedFile을 작성하는 자체 처리기 전에 변경 될 수 있습니다.

3) 최종 참고 사항 : 파일에서 ByteBuf의 쓰기/읽기와 공동 작업 할 수 있는지 100 % 확신 할 수 없으므로 인코더/디코더 (ObjectEncoder/ObjectDecoder)를 살펴보고주의해야합니다. 작동 여부 ...

+0

감사합니다, 서버가 파일을 보내는 것처럼 보이지만 클라이언트가 올바르게 3)에서 설명한대로 디코딩 할 수 없습니다. 'io.netty.handler.codec.TooLongFrameException : 조정 된 프레임 길이가 1048576 : 4292411364 - 삭제됨'을 초과했습니다. 시작 키워드는 무엇입니까? – jussi

+0

내가 제안 할 수있는 것은 두 종류의 트래픽을 모두 자신의 코덱으로 관리하는 것입니다. ObjectDecoder/Coder를 사용하지 않고 HTTP와 마찬가지로 헤더 + 파일 전송과 같은 두 가지를 모두 관리해야하지만 자신의 코덱을 사용해야합니다. LengthFieldBasedFrameDecoder를 참조하십시오. 첫 번째 바이트는 헤더이고, FileRequestProtocol 객체를 생성하는 메시지의 길이, lengthFile 바이트 다음에 ByteBuf (ChunkedFile이 아님)를 기준으로 FileChunkReqWriteHandler에 의해 catch되도록합니다 (SimpleChannelInboundHandler 그것을 잡아야 만한다). –

관련 문제