channel 계속해서 열어두는 방법이 궁금합니다.

3,972 views
Skip to first unread message

kim jeff

unread,
Jan 24, 2016, 5:50:43 AM1/24/16
to Netty Korean User Group
안녕하세요
네티를 서버로 하고 cocos2d 게임엔진(c++)을 이용해서 http통신을 통한
멀티플레이어용 게임을 개발중인 초보 개발자입니다.
"자바 네트워크 소녀 netty"라는 책을 공부하여 사용하고 있는데요
제가 이해한 바로는 클라이언트가 접속하면 새로운 채널을 생성하여
파이프라인에 이벤트핸들러를 추가하고 이벤트 핸들러를 통하여 
클라이언트쪽의 요청을 자동으로 channelRegistered -> channelActive -> channelRead -> ... -> channelUnregistered 순서로 이벤트 핸들러 내에서 자동적으로 실행되는걸로 알고 있습니다.

여기서 저는 채널을 클라이언트가 접속을 종료할때까지 계속 열어두고 데이터를 주고 받고 싶은데
netty 내부적으로 channelUnregistered까지 실행되어 버리는걸 확인하였습니다. 이런 상황에서 어떻게 계속해서 해당 클라이언트의 request에 의해 생성된 채널을 열어놓고 유지할 수 있을까요?

channelGroup을 이용해서 
static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
...
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new HttpSnoopServerInitializer(sslCtx));
Channel ch = b.bind(PORT).sync().channel();
channelGroup.add(ch);

이런식으로 클라이언트 요청에 의해 채널이 생성될때 그룹에 추가해서 나중에 다시 사용하려는 생각인데
channelUnregistered까지 실행되어버려서 저 방법이 안될 것 같습니다.

조언부탁드립니다.
감사합니다.


김경송

unread,
Jan 24, 2016, 8:07:00 PM1/24/16
to Netty Korean User Group
우선 현재까지 이해하신 점은 모두 맞으십니다.

채널이 Unregister로 된다는 것은, 채널이 닫혔다(끊겼다)를 의미하는데요. 여러가지 이유가 있을 수 있습니다.
 1) 서버 쪽에서 소켓을 close 한다
 2) client 쪽에서 소켓을 close 한다
 3) 그외에 여러 예외 상황 (exception이 발생하여 처리되었다던지, network 방화벽이라던지, socket timeout이라던지...)
일단 쉽게 확인 가능한것은 1) 과 2) 인데요.

서버 쪽에서 close 하는 것은 서버쪽 handler 쪽 소스를 보시면서 혹시 ctx.close()나 ctx.channel.close()등 채널을 닫는 소스가 있는지 확인해보세요.
debug가능하시다면 해당소스 부분을 break point걸어서 확인해 보실 수 있으실테고, 여의치 않으시면 로그를 남기셔도 되겠죠.

clinet쪽에서 close하는 것은 client제작 쪽에 문의를 해봐야 할것입니다. socket은 양방향으로 열려있어야 하기 때문에 한쪽에서 끊으면 반대쪽에서도 유지할 수가 없습니다.

서로 확인이 어렵다면, wireShark 같은 패킷 보는 프로그램을 이용해서, RST나 FIN 신호가 어느쪽(server쪽으로부터인지 clinet부터인지)에서 오는지 확인하면,
좀더 확실한 범인(?)을 찾는데 도움이 될 것입니다.

정말 양쪽에서 소켓을 닫는 요소가 없다면, 그 뒤부터는 그 외의 상황에 대해서 네트워크 환경이나 머신 설정등을 확인해봐야할 것입니다.

2016년 1월 24일 일요일 오후 7시 50분 43초 UTC+9, kim jeff 님의 말:

kris jeong

unread,
Jan 24, 2016, 9:10:32 PM1/24/16
to nett...@googlegroups.com
먼저 http통신에 대한 이해가 선행 되어야 할 것 같네요.

기본적으로 HTTP통신은 한번의 요청과 응답이 완료되면 소켓을 닫습니다. 

이건 프로토콜상의 정의입니다.

올려주신 예제코드는 HTTP 예제 이므로 연결이 끊어지는게 정상입니다.

만약 매 요청마다 발생하는 TCP 핸드쉐이크가 부담이 된다고 생각하시거나 

반드시 TCP 연결이 유지되도록 구현하여야 한다면 

TELNET 예제를 참고하시는게 더 도움이 될것 같네요.

본 이메일은 Avast로 보호되는 안전한 컴퓨터에서 발송되었습니다.
www.avast.com

2016년 1월 25일 오전 10:06, 김경송 <maylo...@gmail.com>님이 작성:

--
이 메일은 Google 그룹스 'Netty Korean User Group' 그룹에 가입한 분들에게 전송되는 메시지입니다.
이 그룹에서 탈퇴하고 더 이상 이메일을 받지 않으려면 netty-ko+u...@googlegroups.com에 이메일을 보내세요.
웹에서 이 토론을 보려면 https://groups.google.com/d/msgid/netty-ko/d96ea1b5-1c43-4935-bba9-fe402695c7ff%40googlegroups.com을(를) 방문하세요.

더 많은 옵션을 보려면 https://groups.google.com/d/optout을(를) 방문하세요.

김경송

unread,
Jan 24, 2016, 11:23:53 PM1/24/16
to Netty Korean User Group
중요한 이야기인지는 모르겠으나, HTTP 도 1.1 spec 부터는 keep-alive를 공식적으로 지원합니다. (https://www.w3.org/Protocols/HTTP/1.1/draft-ietf-http-v11-spec-01#Keep-Alive)

2016년 1월 25일 월요일 오전 11시 10분 32초 UTC+9, kris jeong 님의 말:

kim jeff

unread,
Jan 24, 2016, 11:37:16 PM1/24/16
to Netty Korean User Group
keep-alive를 request에 지정한다면 response를 전송한 이후에도
channelUnregistered 함수에 들어가지 않고 채널이 유지된다는 말씀이신가요?

2016년 1월 25일 월요일 오후 1시 23분 53초 UTC+9, 김경송 님의 말:

김경송

unread,
Jan 25, 2016, 12:04:06 AM1/25/16
to Netty Korean User Group
그렇게 구현이 되어 있어야, 채널이 유지가 되겠죠.
아무런 구현도 하지 않았는데.. 자동으로 channel이 유지되지는 않겠죠? ^^;

어느 버전 어떤 ref 소스로 참고하시는지 모르겠습니다만, 기본적인 http 예제를 하나 가져와보면

channelRead 부분에서
if (!writeResponse(trailer, ctx)) {
// If keep-alive is off, close the connection once the content is fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}

위와 같이 호출하고 해당 writeResponse부분에서
boolean keepAlive = HttpHeaders.isKeepAlive(request);
if (keepAlive) {
// Add 'Content-Length' header only for a keep-alive connection.
response.headers().set(CONTENT_LENGTH, response.content().readableBytes());
// Add keep alive header as per:
response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
}

현재 keepAlive 가 clinet요청에 있는지 없는지 확인하여 분기 처리하고 있습니다.
keepAlive가 있다면 Header에 해당 spec을 지원한다는 명시를 해서 response를 반환합니다. (그리고 소켓을 끊지 않습니다.)
만일 keepAlive가 없다면 해당 소켓은 clinet에서 끊으면 정리됩니다.

위의 구현예를 참고하셔서 분석하시고 적용하시면 될것 같습니다.

2016년 1월 25일 월요일 오후 1시 37분 16초 UTC+9, kim jeff 님의 말:

kim jeff

unread,
Jan 25, 2016, 12:07:07 AM1/25/16
to Netty Korean User Group
정말로 감사드립니다.
소스분석해서 공부하고 사용해보겠습니다!
친절한 답변 다시 한 번 감사드립니다.

2016년 1월 25일 월요일 오후 2시 4분 6초 UTC+9, 김경송 님의 말:

kim jeff

unread,
Jan 25, 2016, 12:21:07 AM1/25/16
to Netty Korean User Group
hearder.isKeepAlive로 클라이언트에서 보낸 request가 
keep-alive로 set 되어있는것을 확인했는데
처음 질문에 말씀드린것처럼 channelUnregistered가 자동실행되는것 같습니다.
제가 사용하던 예제는 올려주신 예제와 같은 것으로 하고 있었습니다 
channelUnregistered 함수가 실행된다는 것은 채널이 끊겨버린 것 같은데
keep-alive가 header에 set 되어있으면, 요청에 대한 response를 해줘도
채널을 끊지않고 살아있어 다음 여러 request를 처리 해 줄 수 있을거라고 생각했는데
제 생각이 틀린건가요??

2016년 1월 25일 월요일 오후 2시 4분 6초 UTC+9, 김경송 님의 말:
그렇게 구현이 되어 있어야, 채널이 유지가 되겠죠.

김경송

unread,
Jan 25, 2016, 1:22:32 AM1/25/16
to Netty Korean User Group
kim jeff님이 생각하시는 것은 맞구요,
그래서 제 첫번째 댓글을 보시면 다 맞게 이해하고 계시다고 말씀을 드렸어요.
제 첫번째 댓글을 다시한번 보시고 client에서 끊는지 server에서 끊는지 부터 추적을 해보시고 그 원인을 해결하셔야 합니다!

2016년 1월 25일 월요일 오후 2시 21분 7초 UTC+9, kim jeff 님의 말:
Reply all
Reply to author
Forward
0 new messages