월별 글 목록: 2010년 9월월

넌 블럭(Non-blocking) 소켓채널(SocketChannel)에서 읽기(read) 타임아웃 처리하기..

자바의 기본 소켓채널(SocketChannel)의 read 메서드는 타임아웃(timeout)을 제공하지 않는다. 소켓채널의 socket() 메서드로 받아온 소켓객체에 타임아웃을 설정해도 타임아웃이 먹지 않는다. 기존의 스트림 기반의 네트웍 통신을 하는 애플리케이션이라면 조금 생소할 수도 있으나, read 타임아웃은 미션 크리티컬한 서버에서는 매우 중요한 이슈이다. 타임아웃이 없어서 연결이 종료가 안 되면 서버나 클라이언트가 동작을 멈추게 될 수도 있으니 말이다.

그래서, 넌 블럭(Non-blocking)의 read 메서드에 호출하기 전에 while문으로 둘러싸서 타임아웃 기능을 구현할 수 있다. 이 코드는 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)에서 끝까지 읽어오기..

넌 블러킹(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);
        }
    }

Mapped Statements collection does not contain value xxx.xxx.xxx.xxx 에러

ibatis나 mybatis에서 XML을 사용해서 쿼리문을 작성해서 쿼리를 실행한 경우, 아래와 같은 에러를 볼 수 있다.

java.lang.IllegalArgumentException: Mapped Statements collection does not contain value xxx.xxx.xxx.xxx

이 에러가 나는 겨우, 알면 쉽지만 모르는 경우 찾는게 쉽지 않았다.
이 에러는 매퍼(Mapper)에 선언한 메서드 이름과 매퍼 파일(XML)에 기술한 쿼리문(Select, Insert 등)의 이름이 같지 않아서 발생하게 된다.

위 에러가 발생시키는 예는 다음과 같다.

ex) 인터페이스 이름

public String print(String x) throws Exception;

ex) mapper.xml


<select id="prints" statementType="CALLABLE" parameterType="String" resultType="String">
        .........................
</select>

병행(Concurrent) vs 병렬(Parallel)

병행(Concurrent)과 병렬(Parallel)의 개념에 대한 내용이다. 아래 링크 내용 보면 쉽게 이해할 수 있다.

http://kevinpelgrims.com/blog/2010/08/30/parallel-programming-in-net-introduction/

위 링크의 내용은 다음과 같다.

Concurrent applications tend to create a thread that
handles a whole series of tasks. Most of the time these concurrent
applications create threads because they need an isolated process for a
concurrent event.
Parallel applications divide a process into small tasks
that are executed on seperate threads. Because the tasks are small, the
threads can be divided evenly over the processors, resulting in very
efficient use of a multi-core CPU.

아래 이미지는 병행과 병렬의 차이에 대한 좋은 설명이다.

reactor 프레임웍의 socketchannel의 read 메쏘드 호출을 어디에서??

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

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

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

고민이네.. ㅜㅜ