본문 바로가기

Programming/Java

[Netty] TCP/IP 통신 시 클라이언트에서 전송한 데이터를 못 받아 오는 상황

- 대상 라이버러리 Ver  :  Netty 4.0.33.Final

- 실행환경  :  Windows 10 Home, cmd 창에서 Runnable Jar로 실행


1. 현상


단말기(안드로이드)에서 TCP/IP를 이용한 데이터 통신 시 [ 단말기 -> 서버] 로 보낸 메세지를 receive하지 못하는 경우가 발생. 모든 케이스에서 발생한 문제는 아님. (네티를 사용한 Client에서는 발생하지 않음)



2. 원인


- Server에 있는 아래 코드 부분에서 전달받은 ByteBuf 를 처리해 주지 못한 문제였음.

 ChannelPipeline에 설정해 두었던 DelimiterBaseFrameDecoder가 받은 데이터를 Handler까지 전달하지 못하는 듯 보였음.


@Override
public void initChannel(SocketChannel ch) throws Exception {
	ChannelPipeline pipeline = ch.pipeline();
				
	pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
	pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
	pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));
				
	pipeline.addLast(new ChatClientHandler());
}



3. 해결방안


- Netty Korean User Group의 이희승님 답변 참고 


... 중략 ...


현재 소켓에 어느 정도의 데이터가 들어있는지는 소켓에서 데이터를 다 읽은 후에야 알 수 있습니다.  매번 큰 버퍼를 할당해서 할 

번에 다 읽으려고 하면 실제로 적은 양의 데이터가 들어왔을 때 메모리 낭비가 심하므로, 네티는 처음에는 작은 버퍼에 읽어들여 

보고 상황에 따라 다음 번에 할당할 버퍼의 크기를 동적으로 조정합니다. 


또한, TCP/IP 는 스트리밍 프로토콜이기 때문에 64KiB 를 한 번에 썼다고 해서 받는 쪽에서 그것을 한 번에 다 읽게 

된다는 보장이 없습니다.  네티가 그냥 매번 큰 버퍼를 할당한다 하더라도 서비스에 가해지는 부하가 증가하면서 같은 문제를 겪게 

됩니다. 


따라서 디코더를 작성할 때는 그 점을 고려하여 원하는 만큼은 데이터가 들어오지 않았을 때 적절히 처리해 주어야 겠지요. 


자세한 내용은 User guide 확인 바랍니다: 


  http://netty.io/wiki/user-guide-for-4.x.html#wiki-h3-10


ByteToMessageDecoder를 이용, decode() 메소드를 override하여 해결함.


@Override
public void initChannel(SocketChannel ch) throws Exception {
	ChannelPipeline pipeline = ch.pipeline();
	pipeline.addLast(new ByteToMessageDecoder() {
		@Override
		protected void decode(ChannelHandlerContext ctx, ByteBuf in,<List Object> out) throws Exception {
			out.add(in.readBytes(in.readableBytes()));
		}
	});
						
	pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));
	pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));

	pipeline.addLast(new ChatServerHandler());
}



※ 관련 내용에 대한 피드백이나 개선 사항이 있으시면 언제든 댓글 남겨 주시기 바랍니다.