의 Netty ByteBuf에서 읽을 수있는 데이터가없는 경우 어떻게 알 수 있습니까?

레저 동 :

나는 인 Netty에 새로운 해요. 일 동안 저를 혼란 파일 전송에 대한 문제가 있습니다. 나는 보내려는 이미지 클라이언트에서 서버로 파일을.

아래의 코드는 실행 파일입니다. 하지만 내가 종료 서버는 강제 I는 일반적으로 수신 된 이미지 파일을 열 수 있습니다. 그렇지 않으면 "표시 이 파일을 볼 수있는 권한이없는 것 같습니다. 권한을 확인하고 다시 시도하십시오 ." 나는 가까운 FileOutputStream에 원하는 그래서이 사용 ByteBuf에 데이터 없을 때 ByteBuf.isReadable는 () 하지만, ServerHandler의 방법 channelRead에서 다른 블록에 도달하지 않습니다. 그건 소용 없어.

보내는 경우 게다가, 텍스트 파일을 서버 인 경우, 정상적으로 열 수 있습니다 살아 . 내가 종료 서버로 전송 한 후 모든 시간을 원하지 않는다 . 나에게 그것을 해결하기 위해 몇 가지 제안을주십시오.

이 FileClientHandler입니다

public class FileClientHandler extends ChannelInboundHandlerAdapter {

private int readLength = 8;

@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
    sendFile(ctx.channel());
}

private void sendFile(Channel channel) throws IOException {
    File file = new File("C:\\Users\\xxx\\Desktop\\1.png");
    FileInputStream fis = new FileInputStream(file);
    BufferedInputStream bis = new BufferedInputStream(fis);

    for (;;) {
        byte[] bytes = new byte[readLength];
        int readNum = bis.read(bytes, 0, readLength);
        // System.out.println(readNum);
        if (readNum == -1) {
            bis.close();
            fis.close();
            return;
        }
        sendToServer(bytes, channel, readNum);
    }
}

private void sendToServer(byte[] bytes, Channel channel, int length)
        throws IOException {
    channel.writeAndFlush(Unpooled.copiedBuffer(bytes, 0, length));
}

}

이 FileServerHandler입니다

public class FileServerHandler extends ChannelInboundHandlerAdapter {

private File file = new File("C:\\Users\\xxx\\Desktop\\2.png");
private FileOutputStream fos;

public FileServerHandler() {
    try {
        if (!file.exists()) {
            file.createNewFile();
        } else {
            file.delete();
            file.createNewFile();
        }
        fos = new FileOutputStream(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
        throws Exception {
    try {
        ByteBuf buf = (ByteBuf) msg;
        if (buf.isReadable()) {
            buf.readBytes(fos, buf.readableBytes());
            fos.flush();
        } else {
            System.out.println("I want to close fileoutputstream!");
            buf.release();
            fos.flush();
            fos.close();
        }

    } catch (Exception e) {
        e.printStackTrace();
    }
}
}
Ferrybig :

서버 측 고정

그물코의 세계에서 여러 "이벤트"가 있습니다 :

이러한 "이벤트", 당신은 아마 이미 알고 channelRead(당신이 그것을 사용하기 때문에) 않지만, 당신이 필요로 보이는 또 다른 하나가 있습니다 channelInactive. 이 사람은 때 다른 엔드 포인트 닫힌다 연결 아래라고, 당신은 다음과 같이 사용할 수 있습니다 :

@Override
public void channelInactive(ctx) {
    System.out.println("I want to close fileoutputstream!");
    fos.close();
}

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg)
        throws Exception {
    try {
        ByteBuf buf = (ByteBuf) msg;
        // if (buf.isReadable()) { // a buf should always be readable here
            buf.readBytes(fos, buf.readableBytes());
        //    fos.flush(); // flushing is always done when closing
        //} else {
        //    System.out.println("I want to close fileoutputstream!");
        //    buf.release(); // Should be placed in the finally block
        //    fos.flush();
        //    fos.close();
        //}
    } catch (Exception e) {
         e.printStackTrace();
    } finally {
         buf.release(); // Should always be done, even if writing to the file fails
    }
}

그러나, 어떻게 서버 연결이 종료되었습니다 알고 있나요? 순간 클라이언트는 서버 다운을 종료하고, 대신에 영원히 살아 연결을 유지하는 백그라운드에서 계속 실행되지 않습니다.

클라이언트 측을 고정

제대로 종료 클라이언트의 연결에, 우리가 호출해야 channel.close()하지만, 우리는 할 수 없습니다 직접 삽입 리턴 라인 전에,이 데이터를 전송하고, 네트워크 계층에서 연결을 종료, 잠재적으로 데이터를 삭제 사이의 경쟁 조건이 발생한다.

제대로 이러한 조건을 처리하기 위해 인 Netty는 사용하는 Future비동기 작업 일 후 핸들 이벤트에 코드를 수 있도록 시스템을.

행운이 우리를 위해, 인 Netty 이미 솔루션 빌드가 이를 들어, 우리는 그것을 묶을 필요가있다. 우리의 코드에이 솔루션을 배선하기 위해, 우리는 최신의 트랙을 유지해야 ChannelFuture의 Netty의 쓰기 방법에 의해 방출합니다.

제대로이 솔루션을 구현하기 위해, 우리는 변경 sendToServer쓰기 방법의 결과를 반환합니다 :

private ChannelFuture sendToServer(byte[] bytes, Channel channel, int length)
        throws IOException {
    return channel.writeAndFlush(Unpooled.copiedBuffer(bytes, 0, length));
}

그리고 우리는 우리가 연결을 종료하고자 할 때이 반환 값을 추적하고 솔루션의 Netty의 빌드를 포함하는 리스너를 추가 유지 :

ChannelFuture lastFuture = null;
for (;;) {
    byte[] bytes = new byte[readLength];
    int readNum = bis.read(bytes, 0, readLength);
    // System.out.println(readNum);
    if (readNum == -1) {
        bis.close();
        fis.close();
        if(lastFuture == null) { // When our file is 0 bytes long, this is true
            channel.close();
        } else {
            lastFuture.addListener(ChannelFutureListener.CLOSE);
        }
        return;
    }
    lastFuture = sendToServer(bytes, channel, readNum);
}

추천

출처http://43.154.161.224:23101/article/api/json?id=176305&siteId=1