파일 및 구조화 된 메시지를 전송할 수있는 프로토콜에 대해 netty 파이프 라인을 작성하고 있습니다. 파일 전송은 구조화 된 메시지 (핸드 셰이크)와 파일을 나타내는 바이트 스트림으로 시작됩니다.내 netty 파이프 라인에서 디코딩하는 동안 정확히 5 바이트를 잃어 버리는 이유는 무엇입니까?
+---------+ +---------+
| Client | | Server |
+---------+ +---------+
| |
| Connect (1) |
|--------------------------------------------->|
| |
| Handshake to announce incoming file (2) |
|--------------------------------------------->|
| |
| Acknowledge file transfer (3) |
|<---------------------------------------------|
| |
| Send file (4) |
|--------------------------------------------->|
프로토콜 메시지는 다음과 같습니다 : 입력
+---------+----------------+----------------+
| Length | Type | Actual Message |
| 4 bytes | 1 byte | N bytes |
+---------+----------------+----------------+
들어오는 파일에 대한 정확한 메시지 흐름 (서버, 클라이언트 다른 소프트웨어 내 그물코 구현되는) 다음과 같습니다 핸드 셰이크 메시지의 경우 Actual Message
은 단일 Long
값인 token
으로 구성됩니다.
public class ProtocolDecoder extends ReplayingDecoder<State> {
private Integer msgType;
private Long token;
public enum State {
LENGTH,
MSG_TYPE,
TOKEN
}
public ProtocolDecoder() {
super(State.LENGTH);
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
switch (state()) {
case LENGTH:
// (2) read the message length from the handshake
long messageLength = in.readUnsignedIntLE();
checkpoint(State.MSG_TYPE);
case MSG_TYPE:
// (2) read the message type from the handshake
msgType = in.readBoolean();
checkpoint(State.TOKEN);
case TOKEN:
try {
// (2) read the token from the handshake
token = in.readUnsignedIntLE();
// (3) write back the acknowledgement
ctx.channel().writeAndFlush(new Acknowledgement(token));
// (4) done reading the protocol message
// now switch to the file protocol
ctx.pipeline().addLast(new FileInboundHandler());
// write everything that is still in the buffer to the
// modified pipeline
ByteBuf rest = in.readBytes(super.actualReadableBytes());
out.add(rest);
// remove the protocol handshake decoder and pass
// the rest of this channel to the `FileInboundHandler`
ctx.pipeline().remove(this);
} finally {
reset();
}
break;
default:
throw new Error("Shouldn't reach here.");
}
}
private void reset() {
token = null;
msgType = null;
}
FileInboundHandler
단순히 파일을 생성하고 모든 ByteBuf
들 기록 :
다음은 ReplayingDecoder입니다.
이 문제는 원칙적으로 각 파일이 처음부터 정확히 5 바이트를 놓치는 유일한 문제로 작동합니다.
나는이 개 질문이 :
1) I 파이프 라인의 첫 번째 핸들러로 LoggingHandler
을 넣으면, 내가 소켓의 모든 트래픽이 기록되어 있는지 확인 할 수 있습니다, 내 디코더는 버그가있는 경우에 상관없이?
2) ctx.channel().writeAndFlush()
을 호출 할 때 "아웃 바운드"버퍼 만 플러시합니까? 즉, 인바운드 버퍼에서 아직 소비하지 않은 바이트를 플러시하지 않는다는 것을 의미합니까?
나는 이전 버전의 디코더에서 (모든 경우에';;를 사용한다.) 시도했지만, 그 행동은 동일했다. 또한 [ReplayingDecoder 설명서] (https://github.com/firebase/netty/blob/master/codec/src/main/java/io/netty/handler/codec/ReplayingDecoder.java#L149-L199)는 너무 메커니즘을 통해 가을 - 나는 그 체크 포인트 뒤에 아이디어라고 생각. – pulse00
@ pulse00 음, 이해가가는 것 같습니다. 결국 한 번에 헤더를 읽을 수 있고 끝에있는 파이프 라인에서 디코더가 제거됩니다. 파일 처리기는 무엇입니까?이 프로토콜 헤더가 포함되어 있습니까? –