TCP 서버를 nio 패키지의 클래스를 활용하여 개발하던 중 만난 이슈 입니다.
물론, 서버채널(ServerSocketChannel)은 비동기(configureBlocking 값이 false)인 상황 이였습니다.
네트워크가 끊어진 경우에는 셀렉터의 키 값을 반환(cancle) 하고 체널을 종료(close)를 해 주어야 합니다.
그렇지 않으면 해당 채널은 계속해서 iterator를 통해서 나오기 때문 입니다.
대략 아래처럼 코드를 작성 하였습니다.
//생략..
Selector selector;
{
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
SocketChannel sc= (SocketChannel) key.channel();
if(!sc.isConnected() || !sc.isOpen()) { //요깁니다! 요 조건!!
key.cancel();
sc.close();
}
}
}
위 코드에 의하면 닫혔거나 끊긴 경우에 해당 키 값을 반환(cancle)하고 체널을 종료(close) 하도록 하였습니다.
가져온 소켓체널(SocketChannel) 값이 isConnected 하지 않거나 isOpen 하지 않으면 해당 TCP 연결이 끊어진 것이라 생각 했기 때 문에 위 코드처럼 작성을 하였습니다.
그러나 실제로는 그렇지 않고 읽기 행위가 반복 되었습니다(read)
아래 사진은 읽는(isReadable) 행위를 정의한 구간 입니다.
isConnected와 isOpen이라는 메소드는 실제로 인터넷 선을 물리적으로 뽑았을 때 동작 하였고,
클라이언트가 끊기는 이벤트는 잡히지 않았습니다.
너무 이해가 안되다가 스택오버플로우에서 아래와 같은 내용을 발견 하였습니다.
If the SocketChannel is closed by you, you are closing it,
so you can notify yourself any way you like.
If you want to be notified when the peer closes the connection,
OP_READ will fire and a read will return -1.
* 출처
https://stackoverflow.com/questions/9445973/how-to-be-notified-when-a-socketchannel-is-closed
가장 맨 처음 읽는 바이트의 앞 자릿수 byte 값이 -1 인 경우에는 클라이언트의 접속이 끊긴 것을 의미한다는 내용 이였습니다.(또는 read를 통해 읽은 갯수가 0보다 작은 경우)
그리하여 실제 해당 내용대로 읽기 행동(isReadable) 에서 가장 처음 읽어지는 첫번째 바이트 값이 -1(비동기는 : 0) 인 경우에는 정말로 클라이언트의 종료를 의미 했습니다(반드시 맨 처음 읽을 때 이어야 합니다!)
서버채널(ServerSocketChannel)과 셀렉터(Selector)를 통해서 "종료" 이벤트를 정확하게 감지 하려면,
1.가장 처음 읽은 바이트의 값을 확인
2. read 메소드를 통해서 나온 값이 0 보다 작을때
클라이언트와 네트워크가 종료된 것으로 작업하면 되겠습니다!
문의사항 또는 틀린 부분은 언제든 연락주세요! 👻
'Java(자바)' 카테고리의 다른 글
ServerSocketChannel, SocketChannel read write 메소드 사용시 주의해야 할 점 (4) | 2022.12.15 |
---|---|
Java Text blocks(자바 텍스트 블럭) (0) | 2022.03.11 |
Java 클래스 컴파일 버전 확인(Java class check version, javap) (0) | 2021.11.22 |
Java Map 다양한 데이터 정렬하기(자바 맵 정렬 - 2) (0) | 2020.11.05 |
Javax mail 참조 및 수신기능이 되지 않을 때(Java cc, to not working) (0) | 2020.08.31 |
댓글