SocketChannel의 read 메쏘드는 timeout이 존재하지 않습니다.
혹, SocketChannel 객체의 .socket() 메쏘드로  소켓객체의  타임아웃을 세팅해도 먹지 않죠.. ^^;;
그래서, non-blocking의 read 메쏘드에 대한 timeout은 busy waiting하는 형태로 타임아웃을 줄 수 있겠습니다..

                // 20초               
                long timeout = 20 * 1000;  
                long stime = new Date().getTime();
                long rtime = 0L;
               
                int rvalue =0;
                int rvalues = 0;
                while (rtime < timeout ) {
                    rtime = System.currentTimeMillis() - stime;
                    rvalue = channel.read(rbuffer);
                    if(rvalue == -1)
                        throw new Exception("connection closed");
                   
                    rvalues = rvalues + rvalue;
                    if(rtime > timeout)
                        throw new Exception("read timeout exception");

                    if(rvalues >= 4)
                        break;
                }

저작자 표시
non-blocking SocketChannel에서 끝까지 읽어오는 코드입니다.
개인적으로 헤더 8byte, 헤더의 앞의 4byte를 전체 패킷을 길이로 잡습니다.
그리고, 아래처럼 SocketChannel에서 packet handling variables와 같이 패킷을 끝까지 다 읽어 들입니다.
아래 내용은 non-block으로 대용량의 바이너리 데이타를 읽어들이기 위해서 꼭 필요한 내용일 듯 합니다.

* read() 내용

    //// packet handling variables
    private int fullsize = 0;
    private int readedsize =0;
    private int minsize = 8;
   
    @Override
    public void read() {       
        try {
            // 읽기
            int rbytes = this.channel.read(rbuffer);
                   
            // 연결종료
            if (rbytes == -1) {
                ((ChannelListener)this.listener).disconnected(this);
                this.close();
                return;
            }
   
            // 버퍼에 내용이 없는 경우
            if (rbytes == 0) {
                this.channel.configureBlocking(false);
                this.handle();
                return;
            }
           
            // 읽은 바이트 갯수를 증감시킨다.
            readedsize += rbytes;   
            rbufferList.add(this.copy(this.rbuffer, rbytes));
           
            // 최소 패킷의 길이에서 패킷을 전체 길이를 리턴한다.
            if(readedsize >= minsize && this.fullsize == 0) {
                this.fullsize = this.createResultBuffer().getInt();
                for(int i=0; i< this.rbufferList.size(); i++) {
                    this.rbufferList.get(i).position(0);
                }
            }
           
            // 패킷을 다 읽어 들였다.
            if(fullsize == readedsize) {
                ((ChannelListener)this.listener).arrived(this,this.createResultBuffer());
            }
           
            this.channel.configureBlocking(false);
            this.handle();
        } catch(Exception e) { // disconnected
            try {
                this.close();
            } catch(IOException ie) {
                new CallbackExceptionHandler().handle(ie);
            }
           
            ((ChannelListener)this.listener).disconnected(this);
        }
    }

저작자 표시
흠...
현재 개발된 프레임웍의 구조는 master, slave reactor가 있고.. slave reactor가 네트웍 이벤트를 디스패칭을 하고있는 구조이고, 또 socketchannel의 read 메쏘드를 통해서 bytebuffer를 worker 쓰레드에 넘기는 구조인데요..

최근에 큰 사이즈의 이미지를 전송하다 보니....
worker 쓰레드에서 socketchannel의 read 메쏘드를 호출하는 것이 더 맞아보이기도 하고..

흠.. socketchannel의 read 메쏘드를 호출하는 객체가 slave reactor가 되야 될까요?? 아님 worker 쓰레드가 되야 될까요??

고민이네.. ㅜㅜ

저작자 표시

소켓 연결 확인하기..

from Java 2010/03/03 12:19
소켓을 기반으로 풀링을 하는 라이브러리를 개발할 시에 보통 소켓 클래스의 isconnected 라는 상태변수를 통해서 소켓의 연결상태를 확인할 수 있으나, 정확한 정보는 아니죠.. isconnected라는 변수는, 마지막 네트웍 이벤트를 처리한 소켓의 연결 상태이기 때문이죠.. 그래서 확실하게 풀을 관리하기 위해서는 네트웍 이벤트를 발생시켜 보는것이 Java에서는 해결책이라고 봐야 될듯 합니다. 
아래코드는 SocketChannel이 non-block인 상태를 기준으로, read 메쏘드를 호출했을 경우, 리턴값을 보고 상태를 확인하는 코드입니다.

int  readbytes = socketChannel.read(buf);

// 연결이 되어 있음..
if(readbytes == 0)
// 끊어졌네요.
if (readbytes == -1)
// 리시브된 데이타가 있네요..
if(readbytes >0)

소켓 풀링을 관리하는 매니저 클래스가 풀에 들어있는 소켓의 read 이벤트를 주기적으로 호출해보면, socket의 연결상태를 잘 유지할 수 있을 것입니다. ^^
Selector를 통해서 클라이언트 SocketChannel을 등록하고 read 이벤트가 발생할 경우, 폴링을 하면서 read를 하지만 계속 0을 리턴하는 경우가 있습니다.. 그럴경우, read(ByteBuffer buffer)의 buffer의 position을 잘못 세팅했을 경우 발생을 합니다. 어떻게 보면 쉬운 버그이지만, 쉽게 찾아지지가 않는 다는.. ^^;;

'Java' 카테고리의 다른 글

POJO와 관련된 용어들..  (1) 2008/09/24
File 내용 추가하기..  (0) 2008/09/24
SocketChannel에서 read()시에 계속 0을 리턴할 경우..  (0) 2008/09/23
Selector 및 SelectionKey 클래스 내용..  (0) 2008/09/05
this keyword 의미  (0) 2008/08/25