본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Java(자바)

Nio 패키지 TCP 서버 종료 이벤트(Selector, ServerSocketChannel)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2023. 2. 15.

 

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) 행위를 정의한 구간 입니다.

요기 todo라는 함수는 읽는 행위를 정의한 함수 입니다.

 

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

 

How to be notified when a SocketChannel is closed?

I want to be notified when a SocketChannel has its close method called. My first thought was to create a wrapper which notifies a listener when the implCloseSelectableChannel method is called (sinc...

stackoverflow.com

 

가장 맨 처음 읽는 바이트의 앞 자릿수 byte 값이 -1 인 경우에는 클라이언트의 접속이 끊긴 것을 의미한다는 내용 이였습니다.(또는 read를 통해 읽은 갯수가 0보다 작은 경우)

요기 read 값이 0보다 작은경우!!

 

그리하여 실제 해당 내용대로 읽기 행동(isReadable) 에서 가장 처음 읽어지는 첫번째 바이트 값이 -1(비동기는 : 0) 인 경우에는 정말로 클라이언트의 종료를 의미 했습니다(반드시 맨 처음 읽을 때 이어야 합니다!)

 

서버채널(ServerSocketChannel)과 셀렉터(Selector)를 통해서 "종료" 이벤트를 정확하게 감지 하려면,

1.가장 처음 읽은 바이트의 값을 확인

2. read 메소드를 통해서 나온 값이 0 보다 작을때

클라이언트와 네트워크가 종료된 것으로 작업하면 되겠습니다!

 

문의사항 또는 틀린 부분은 언제든 연락주세요! 👻

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글