본문 바로가기

공부/컴퓨터

서버 만들때 읽어 볼 글 - non-blocking I/O , Thread Pool

반응형
제목 : Re: chatting프로그램 가이드
글쓴이: 신형주(shin7688)   2002/10/11 02:58:47  조회수:141  줄수:88
  
자바 처음짜는 사람을 위한 chatting프로그램 가이드

네트웍은 모르더라도 OOP는 필요한것 같구요.
Chat이란 사용자가 connection을 시작해서 이 세션이 끊어질때까지 문자를 주고 받는것을
의미 합니당. 서버 프로그램에서는 기초적으로 프로그램을 볼께요.
최고의 서버는 fault-tolerance, load-balancing, sessioning을 제공하는 솔루션이어야
하지만 처음에는 간단한 데이타 교환이 좋지요.

기초:
1.클라이언트가 구동하기전에 서버는 구동해야 하죠.
2.커넥션을 얻기 위해서 기다려야 되고 물론 port(당연 한대의 컴퓨터를 기준으로요)가
  열려져 있는 상태로요.
3.client, server간 통신을 위해서 Socket object를 통하여 통신을 하죠
4.Socket은 InputStream과 OutputStream을 가지고 있어서 데이타를 읽고 쓸수 있죠.

서버 프로그램 계획:
1.서버는 커넥션이 초기화 되기 전까지는 기다리는 거죠.
2.ServerSocket은 port에서 새로운 커넥션이 들어 올때 Socket을 생성하죠.
3.이때 주의 할점은 클라이언트는 예고 없는 시점에 마구 들어오고 이때 멀티쓰레드를
사용하죠.

Server Side code:
private void listen( int port ) throws IOException {
    ss = new ServerSocket( port );
    while (true) {
        Socket s = ss.accept();
        DataOutputStream dout = new DataOutputStream( s.getOutputStream() );
        // HashTable인 outputStreams에 데이타를 저장 하저.
        outputStreams.put( s, dout );
        // 새로운 thread 생성을 위해서 있는 ServerThread
        new ServerThread( this, s );
    }
}

다룰것:
1.Server Class
2.While-Accept Loop
3.Per-Thread Class(쓰레드 풀 필요 없어요)
4.While-Read/Write Loop (Server)
5.Removing Dead Connections
6.Client Class
7.While-Read/Write Loop (Client)

쓰레드 뭔지 알죠:
1.일반적인 쓰레드라는 것은 코드를 한라인씩 읽어가는 프로세스 이져.
2.근데 멀티 쓰레드는 동시간에 활동하고 있는 쓰레드를 의미하져.
3.데이타에 대한 접근뿐만 아니라 효율적으로 사용 할수 있죠. 비동기의 장점이라고 할까요.
4.많은 사용자 처리에 쉽게 처리 할수도 있고요.


통신 프로토콜:
-DataInputStream 과 DataOutputStream    를 쓰느 이유는 Low-level(Integer, String 등)에
대한 포멧의 변화없어서요
-DataOutputStream으로 쓰면 Integer을 쓰면  DataInputStream에서는 변화 없이 받죠.
1.한 유저가 창에 메시지를 보내면 DataInputStream를 통하여 message를 보내죠.
2.서버가 DataInputStream로 메시지 받아서 DataOutputStream으로 모든 유저에게
  message를 보내죠.
3.사용자들은 DataInputStream로 데이타를 받고요.


public void run() {
    try {
        DataInputStream din =
            new DataInputStream( socket.getInputStream() );
        while (true) {
            String message = din.readUTF();
            // 모든 사용자에게 메시지 보내여
            server.sendToAll( message );
        }
    } catch( IOException ie ) {
        ie.printStackTrace();
    } finally {
        // connection을 클로즈 해요
        server.removeConnection( socket );
    }
}


Thread각각이 cpu자원과 메모리(0.5MB)의 스택을 가지고 있죠.
Stack은 heap속의 인스턴스로의 reference가 들어 있으므로, GC는 Stack영역도쭉 검사하죠.
1000개의 쓰레드 = 수천MB어치의 stack을 GC마다 검색을 하게 되죠
쓰레드가 늘어난다고 고성능이 되는 것은 아니죠.
JVM 리소스의 과다 사용은 처리를 늦추는 결과를 가져 오구요.
처리용 쓰레드를 적당수로 낮추고[chatting은 ThreadPool사용 말아야],
복수의 JVM을 사용하도록 검토하는 것이 좋죠.

내일 워크삽 가네요. 밤이 늦어서 2부는 일요일에 쓰죠



제목 : Re: 채팅에서 쓰레드풀 이용하지 말아야??
글쓴이: 나승민(rulu)   2002/10/11 10:12:51  조회수:89  줄수:19
  
채팅은 Thread pool을 사용하지 말아야하는 이유가 어떤건지 알고 싶습니다
단지 쓰레드개수가 많다고 성능이 좋아지는건 아니라는데 공감합니다.

짧은 생각인지 모르겠으나 저의 생각으로는 자바경우 ServerSocket.accept() 직후에
쓰레드 객체를 생성하는 구조는 오히려 객체생성시간을 많이 차지하므로, 사용자의
접속시간이 길어지는 단점이 있는걸로 알고 있습니다.
그래서 쓰레드풀을 사용한다고 알고 있는데요. 제가 잘못알고 있는지 궁금하네요.

그레고 쓰레드풀을 이용하므로서  GC(Garbage collection)로 인한 부하를 더 감소할 수
있는걸로 알고 있습니다만.. 왜냐면.. 사용자 접속이 끊겨도 해당 쓰레드는 버리지
않으므로 즉, GC의 대상이 안된다는겁니다.
그러나 쓰레드풀을 이용하지않는구조는 사용자 접속이 끊어질 때마다. GC의 대상이
되므로, 매번 불필요한  GC를 수행하여 서버에 부담을 주는걸로 알고 있는데요,
이 또한 제가 잘못 알고 있는건지  정확히 지적해주시면 좋겠습니다.

사실 쓰레드의 동작 메카니즘을 제대로 이해하지 않은 상태에서 채팅을 만들다 보니
어려운점이 한두가지가 아닙니다.

바쁘실텐데.. 리플달아주신 신형주님께 감사드립니다.


제목 : 쓰레드갯수 & 소켓풀링(Socket Pooling) [질문]
글쓴이: 나승민(rulu)   2002/10/11 17:13:09  조회수:171  줄수:26
  
이원영님의   'TCP/IP Socket 프로그램 구현시 고려사항' 글을 잘 읽어 보았습니다
TCP/IP Socket 프로그램 구현시 고려사항
http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=javatip&c=r_p&n=1009171849

저 또한 이글을 왜 이제야 읽게되었는지 안타까운 마음입니다.. 그나마 다행이라면 다행,,

TCP/IP Socket 프로그램 작성시 이원영님이 제시한 4가지 방식중 Thread Pooling을 이용한
방식에서 한가지 궁금한 점이 있습니다.
제가 구현한 방식중에 실수한 점이라고도 생각합니다만, Pool에 담아둘 쓰레드의 개수라는게
클라이언트에게 서비스할 기능을 분류하여 쓰레드로 처리한 것이 맞는지요?
저의 경우 클라이언트 1명당 쓰레드 1개로 생성을하여 풀에 담아두고 있습니다..
예를들어 서버 1대에 동시접속자수를 1000명으로 잡을 때.. 서버에서 풀에 담아둘 쓰레드
개수는 1000개가 되는 것입니다.. 현재는 이런 구조로 되어있습니다..
구조상 문제가 있는지 알고 싶습니다..

두번째로 Socket Pool을 이용하는 구조에서 한가지 궁금한게 있습니다하나의 클라이언트가
TCP/IP Socket 연결을 Pool에서 하나 할당 받아서 통신하는 도중에 클라이언트가 로그아웃
하기전까지는 해당 Socket과 계속 연결된 상태인지 아니면.. 메시지를 주고 받을 때만
Pool에서 하나의 Socket을 할당해서 그때 그때 통신을 하는지 궁금합니다.
만일 후자의 경우라면,, 실시간 쪽지같은건 수신이 불가능할거 같은 문제가 있겠구요.
DB Connection Pool의 경우는 후자의 경우라고 생각합니다만..

아무튼 Socket Pooling 이 어떤식을 동작하는지 Client 와 Server Node로 연관지어
설명해주시면 이해하는데 큰 도움이 될거 같습니다

명확한 설명을 주시면 감사하겠습니다



제목 : Re: 비동기 통신은 서버간에
글쓴이: 김홍구(Icoo)   2002/10/11 17:22:40  조회수:62  줄수:17
  
이원영님께서 말씀하신 방법중 Thread Pooling 을 이용하는 방식은 비동기 통신을 말씀하시는
걸로 알고 있습니다..(읽은지 좀 오래되서 기억이 가물가물.. ^^;;)
비동기는 송신하는넘 수신하는 넘을 따로 분리 해서.. 송신은 계속 송신 수신은 계속 수신..
이렇게 하는 방식으로 클라이언트 가 직접 접속하는 방식으로는 적합하지 않을것 같습니다.

보통 비동기 통신은 서버간에 많이 사용하지요.
비지니스로직 서버 <---> 웹서버. 이런 사이에서..

비동기 통신이다 보니 클라이언트 수만큼 스레드가 늘어 나는 방식이 아니라, 보통 10개
안쪽의 수를 사용하구요..  송신 10개 수신 10개... 이런식으로...

그리고 서버에 개인 클라이언트가 직접 접속하는 방식이면.(가령 갬이나,채팅같이)
Socket Pooling이 전혀 의미가 없지요... 헐헐헐... 어짜피 혼자 쓰니까...
그리고 서버 입장에서는 당근히 전혀.. 의미가.. 없지요..

잘못된 내용있으면.. 올려 주십시오.. 그럼. (--) (__) (--)



제목 : Re: Socket Pooling이 의미가 없다구요
글쓴이: 나승민(rulu)   2002/10/11 17:35:38  조회수:60  줄수:11
  
저의 경우 채팅서버를 구현중에 있습니다
구조 및 설계를 제대로 안잡고(몰라서ㅡ.ㅡ) 구현하다보니.. 다시 원점으로 돌아오고
말았습니다.

겜이나 채팅같은 프로그램에서는 Socket Pooling이 전혀 의미가 없다고 하셨는데 정말
그런가요? Pooling이란것은 제한된 자원을 다수 사용자가 공유하는 개념인데, 채팅같은
클라이언트가 많은 구조에서 더 필요하지 않을까요?

제가 아직은 Socket Pooling 에 대해서 제대로 이해하지 못하고 있는 상태라서
이해해주세요.



제목 : Re: 채팅서버에서 Connection Pool이 무의미한 이유
글쓴이: 김홍구(Icoo)   2002/10/11 19:25:15  조회수:76  줄수:25
  
가령 Client와 Server 입장에서 Pooling을 생각 해보지요..

우선 Client... 흠... 어짜피 1나의 Connection만 있으면 됩니다.(필요 없지요..--;;)

다음 Server Connection Pool을 어떻게 구성 하실것인가요?

Client가 다 틀린넘들입니다. Pool을 만들수가 없지요..

Pool은

+-------------+  Tcp/IP                 +----------+
|                    |                             |               |  ------------ 다수의 사용자
| 업무Server    | ------------------ |  웹서버    |  ------------
|                    |                             |               |  ------------
+-------------+                             +----------+

위와 같이 구성된 그림에서 업무 서버와 웹서버 사이에서 사용할때 유용합니다.
업무 서버입장에서는 클라이언트에 해당하는 서버가 제한적이고 어짜피계속 요청이
오기때문에 한번 맺은 컨넥션으로 계속 통신 해도 상관없습니다.

그러나 채팅서버에 해당하는 넘은 웝서버와 일반 사용자에 해당하는 구간인데, 이구간에서는
접속하는 사용자를 알수도 없고 너무 많고...
A라는 사용자와 맺은 접속을 B라는 사용자가 사용하는것도 불가능하기 때문에 소용 없다고
했던것입니다.



제목 : Re: chatting프로그램 가이드(두번째)
글쓴이: 신형주(shin7688)   2002/10/13 14:54:33  조회수:139  줄수:158
  
Connection의 제거:
Server object를 사용하고 있는 Per-Thread는 connection이 client에 의해서 끊어질때
사용하고 있던 Socket을 채팅방의 인원에서 제거하고 Socket을 닫아야 하죠.

server.removeConnection( socket );
는 connection이 정상 상태의 종료(사용자가 종료를 선택)또는 다른 이유 Client와 끊어질때
서버가 connection을 제거 할수 있게 만든 거죠. 이 부분에서 중요한것은 이런 종료 상태를
서버에게 알리는 것이 중요하구요. 서버는 채팅방 리스트에서 제거하고 서버는 더 이상
더 이상 Client와 connection상태가 아닌 Socket에 메시지는 보내는데 자원을 낭비하지
않게되죠.

Connection의 제거의 중요성:
죽은 connection들을 제거 하는것은 처음 서버를 만드는 사람이 자주 잊어서 구현하지 않기
때문에 중요한 요소인데도 구현되지 않은 경우가 많죠.
만약에 현재 Connection의 제거를 구현 하지 않았다면 어떻게 되는지 한번 생각 해보는 것도
좋죠.그러면 서버는 속도가 점점더 느려질거에요. 그리고 메모리는 점점더 많이 차지 하게
되겠죠.서버 프로세스는 메시지를 보낼때마다 프로세스는 Exception으로 폭주 하겠죠.
죽어있는 connection들 에게 메시지를 보내면 메시지를 보낼수 없게되죠.
일반적인 채팅 서버는 5초마다 한번씩 메시지를 보내고 사용자는 평균 15분 동안 채팅을
하죠. 이것이 의미하는 것을 생각해보면 200명의 사용자가 같은 채팅방에서 채팅을 한다고
예상을 하고 많은 사용자들이 connection도 하고 disconnection도 하면서 200명정도의
사용자들을 유지한다고 치면 24시간 후에는 약 2만명의 사용자들이 서버의 케넥션에 접속해
있는 결과를 예측하죠. 첫날 하루가 지나고 나서도 실제 채팅방에 있는 사용자는
200명이고요. 약 1만8천명이 사용 했던 죽은 connection을 서버는 보유하고 있겠죠.
만약 당신이 만든 서버에 죽은 connection을 처리 하지 않는다면 메시지를 보내고 실패하고
시간을 소비하게 되죠. 서버는 통신시간보다 System.out으로 Exception을 처리 하는 시간이
더 많아진다는 거죠.


The Client:
서버는 이정도에서 끝내고요. Client쪽을 보죠.
보통 서버는 새로운 connection을 위해서 wait한 상태에 있고 connection의 요청이 오면
Server의 Per_Thread는 ServerSocket에 의해서 connection을 하죠.
그러면 클라이언트는 어떻죠?
클라이언트는 applet로 구성되어 있을테죠.
자바 application고 웹페이지에서 사용하길 원하기 때문이죠.

GUI:
Applet은 간단히 사용자간 통신을 할수 있는 GUI인터페이스를 가지고 있죠.
클라이언트는 TextField에 입력하고 그 순간에 서버에게 데이타를 보내죠.
처음 GUI초기 구성은 아래처럼 초기화를 하죠.

public class Client extends Panel implements Runnable {
        private TextField tf = new TextField();
        private TextArea ta = new TextArea();  
        public Client( String host, int port ) {
                // 화면 setup
                setLayout( new BorderLayout() );
                add( "North", tf );
                add( "Center", ta );
                //문자 입력하고 enter치면 메시지 가죠.
                tf.addActionListener( new ActionListener() {
                        public void actionPerformed( ActionEvent e ) {
                                processMessage( e.getActionCommand() );
                        }
                } );
        //중간생략
}        

TextField에 문자 입력하고서 어떤액션이 일어나면 모든 유저의 TextArea에 문자열이
보여지죠. 문자열이 입력되면 DataOutputStream을 이용하여 메시지를 보내는
processMessage()사용하죠.


서버에 연결:
클라이언트는 서버에 연결을 하고 메시지를 받는 Thread를 만들죠.

//서버 연결
try {
        // connection 초기화
        socket = new Socket( host, port );
        // 서버 연결 확인
        System.out.println( "connected to "+socket );
        // socket으로부터 DataInput/Output streams 취득
        din = new DataInputStream( socket.getInputStream() );
        dout = new DataOutputStream( socket.getOutputStream() );
        // 메시지를 받기 위해서 background thread를 만들어야죠
        new Thread( this ).start();
} catch( IOException ie ) {
        System.out.println( ie );
}

사용자 입력:
Applet이란 FrameWork은 윈도우즈에서 message를 입력하면 입력event를 통하여 필요한
작업을 하죠. event를 받기전까지는 wait상태에 있는거죠.
아래의 경우와 같이 사용자가 입력받으면 inner class에서 processMessage()를 호출하는
형태죠. 이메소드는 사용자가 입력한 문자열을 받는 역할을 하고, 서버에 메시지를 보내고
TextField를 지우죠.


// 사용자 입력 데이타를 가지고 호출
private void processMessage( String message ) {
        try {
                // 서버에게 보낸다.
                dout.writeUTF( message );
                // TextField를 지우기
                tf.setText( "" );
        } catch( IOException ie ) { System.out.println( ie ); }
}


사용자 출력:
클라이언트 프로그램을 GUI이벤트 기반으로만 움직이지는 않죠.
또 하나 움직이는 이벤트가 있는데 네트웍 이벤트라는 것이 있죠.
서버로부터 오는 데이타를 기다리는 것이 바로 그것이죠.
사용자 입력은 이벤트 처리를 GUI framework을 이용했지만 사용자 출력을 위한 network
event처리는 직접 구현을 해야하죠. 그래서 이것을 Background thread를 이용하여
while-read/write loop를 run 하죠


while-read/write loop:
서버에서 read/write loop를 가진것처럼 클라이언트도 가지고 있죠.
서버와 같이 메시지를 받아서 TextArea에 뿌려 주는 역할을 하죠.
그리고 loop로 돌아와서 다음 메시지를 기다리죠.

// Background thread: 메시지를 TextArea에 뿌려준다.
public void run() {
        try {
                // Receive messages one-by-one, forever
                // 메시지를 계속해서 받아 들이는 역할을 한다.
                while (true) {
                        // 다음 메시지를 받는다.
                        String message = din.readUTF();
                        // TextArea에 메시지를 뿌린다.
                        ta.append( message+"\n" );
                }
        } catch( IOException ie ) { System.out.println( ie ); }
}
L

제한적 사항(단순한 Socket모델):
멀티 Thread 채팅 프로그램은 이대로 완전히 끝난것인가의 의문이 남을 것에요
채팅방이 유일하나 하나만 있다는 가정하에 모든 메시지 처리를 하게 두었죠.
이런 채팅 시스템은 상용에서 사용할때는 문제점을 가질수 밨에 없어요.
왜냐하면 사용자는 채팅방을 여러개로 나누는 것을 원할테니까요.
또한 채팅방에 들어 갈수 있는 권한의 선택도 없고 채팅방을 매개체로 통신하지도 않지요.
서버에서는 sendToAll()을 사용해서 모든 사용자에게 메시지를 보내지만 상업적인
채팅서버는 구분을 해서 메시지를 포워딩 할 시스템을 가지고 있죠.


제한적 사항(너무 많은 Thread):
클라이언트마다 Thread를 만든다는 것은 좋은 아이디어가 아니죠.
많은 Thread들이 있고 sleep상태에 있다 하더라도 시스템이 다운 될수 있는 가능성은 있죠.
무엇보다 중요한것은 한번 프로그램을 만들어 돌려 보는거죠.
왜냐면 시도없이 Thread의 성능을 측정하기는 어렵잖아요.
테스트를 하다 보면 많은 Thread이 접속을 하다보면 문제점이 발생하고 채팅 솔루션은 더욱더
복잡해지죠. JVM은 이런 많은 쓰레드를 처리를 하지 못할테고 고객은 당신이 만든 솔루션에
불평을 할거에요.


제한적 사항(ThreadPool):
매번 생겨나는 새 Thread는 시스템 자원을 소비하죠. Thread를 만드는데는 CPU사이클이
걸리고 각 스레드는 시스템 자원을 소비하는 스택구조를 사용하고 있고요. Thread가
증가할때마다 Thread overhead 에 의해 더 많은 시간을 소비하게 됩니다. 결국 채팅 시스템은
연결 서비스보다 Thread관리에 더 많은 시간을 소비하게 되죠. 스레드의 증가는 클라이언트
서비스 시간을 증가 시키는 원인이 되죠. Thread는 되독록이면 최소화 시키거나 재사용을
해야 하는데 채팅 시스템은 사용자당 사용시간이 15분 가량  사용 되어 지므로 ThreadPool을
사용 해봐야 의미가 없기 때문에 고정된 쓰레드를 만들어 봐야 소용이 없죠.


제목 : Re: 초기 소스에 문제가 있는듯 한데요..
글쓴이: 명랑폐인™(merong)   2002/10/13 22:16:49  조회수:43  줄수:19
    
comunicate() 메소드인가요?
거기보면 socket 객체를 넘겨주었을때, 계속해서 stream 객체를 여는군요...
제 생각이 맞다면, 메모리 아웃이나, 기타 다른 resource 에러가 발생할것 같은데요..
메세지가 있을때마다 스트림을 생성시킨다는게 좀 이상하군요..(제가 코드를 잘 못
본걸까요?)

그리고, 채팅 프로그램에는 쓰레드 풀링을 사용하는게 좋습니다. 소켓은 풀링할 대상이
아닙니다. TCP/IP로 사용자와 서버간에 1:1 로 연결되어 있는 상태에서 풀링을 한다는거
자체가 말이 안되는듯합니다.

그러나 nio를 사용하지 않는 일반 blocking 메소드를 사용하는 채팅 프로그램이라면,
사용자가 입력이 없을경우는 thread 는 sleep 되거나 read input stream 에서 blocking
되어 있거나 둘중에 하나일테니 말이죠..

client에서 데이타가 오면 blocking이 해제 되면서 다음 작업을 수행하게 될테니, 그
부분에서 Pool에서 thread 를 가져다가 작업을 시키고, 작업이 없으면 다시 thread를
pool에 집어 넣는것이죠..

그럼..


제목 : Re: 메시지 수신부에서 non-blocking I/O  사용(nio패키지) ?
글쓴이: 나승민(rulu)   2002/10/14 01:48:23  조회수:90  줄수:49
  

**^.^**
채팅에서 소켓풀에 대한 부분은 의미가 없다는데 공감하구요..

쓰레드풀을 사용할지 말지는 한번 더 고려를 해볼 문제라고 생각합니다(테스트가
필요하겠네요^^) Allen Holub이란 사람이 쓴 책('쓰레드 능숙하게 다루기)에 서 저자는
쓰레드 객체 생성시간이 많이 걸리므로 쓰레드 풀을 사용하기를 권장하고 있습니다
그러나 Scott Oaks & Henry Wong 라는 분이 쓴 책 자바쓰레드(번역서) -- O'Reilly
한빛미디어출판에서 보면은 쓰레드 객체 생성이간이 풀을 사용할 때와 사용하지 않을 때
별 차이가 나지 않는다고 얘기하고 있습니다..  
제 생각으로는 쓰레드 객체생성을 하는데 걸리는 시간은 클라이언트가 느끼는 상대적
시간이라고 생각이됩니다. 즉 클라이언트가 느끼기에 오래걸린다 싶으면 쓰레드풀을
사용하면 좋겠죠..

신형주님이 올린 chatting프로그램 가이드(두번째)에서 제한적 사항(너무 많은 Thread):
글에 대한 부분입니다..
사용자 마다 쓰레드를 만든다는것은 좋은 아이디어가 아니다.. 저도 그리생각합니다
하지만, 일단 소켓이 연결된(서버-클라이언트간) 후에는 클라이언트가 언제 어느때 ,
메시지를 보낼지 알수 없기 때문에,  사용자별로 읽기-쓰기 부분에 대한 쓰레드를 생성해야
되지 않을까 하는데요.. 쓰레드를 몇개로 구성할지, 그리고 어떻게 분류해서 기능적으로
쓰레드를 구성할지도 중요하지만,,  더 중요한건.

제가 구현하면서 고생하고 있는 부분입니다만 C/S간에 소켓연결이 일단 이루어진다음에
서버쪽에서 메시지를 수신하는 부분에서 blocking I/O를 사용하느냐 non-blocking I/O 를
사용하는가가 상당히 중요한 부분이라고 생각합니다..
당연히 성능상 non-blocking I/O를 고려하고 있습니다
제가 첨에 첨부한 소스코드에서는 --------------->
// Client(사용자)로부터 데이터 수신
while(true){
        lm_oIs = socket.getInputStream();                                        
        lm_lSize = lm_oIs.available();
        if(lm_lSize>0){
                lm_oOis = new ObjectInputStream(lm_oIs);
                lm_oRMesg = (Hashtable)lm_oOis.readObject();
                
                // 이 Terminal Server에 연결된 클라이언트에게 메시지 전송
                sendPacket(lm_oRMesg);
        }else{        
                Thread.sleep(20);
        }
}
나름대로 non-blocking 읽기를 구현하고 있습니다  '자바 쓰레드(한빛미디어)' 책에서는
블록킹되지않는 I/O 중 폴링(Polling) 형태에 해당하고 있습니다.
그런데 위 코드의 문제점은 20 mili seconds 가 지나고 난후 매번 CPU자원을 소비하게된다는
것입니다.  수신한 메시지가 있든 없든지 간에 말입니다..
명랑폐인님이 말씀하신 nio 패키지에 저도 관심이 많습니다(보고있는 중...)
혹시 위 코드를 대체할만한 좋은 예제라도 있는지 궁금합니다.
그리고 JDK1.4에서 발표한 nio패키지를 이용하여 서버 코드를 구성한다고 할 때..
클라이언트는 애플릿을(JDK1.1.8) 쓸수 밖에 없는 구조인데.. 문제가 없는지 궁금합니다



제목 : Re: available구문이 잘못된것 아닌가요
글쓴이: 신형주(shin7688)   2002/10/10 17:18:27  조회수:62  줄수:7
  
lm_lSize는 메시지 교환 하지 않으면 리턴 값이 0(추출할수 있는 데이타수) 이잖아요.
근데 while(lm_lSize==0) 이렇게 구현된 부분이 메모리 소모가 심각 할것 같네요.

입력스트림을 조사하는 InputStream의 available을 조사하고 입력이 있는 경우에만
처리를 해야 하지 않을까요.
이 화일문안의 구조는 잘 모르겠구요. 데이타를 얻었을때만 while(lm_lSize>0)
이었을때만 잘동을 해야 하지 않을까 하네요.


제목 : Re: 입력스트림 조사에 대한 더 좋은방안?
글쓴이: 나승민(rulu)   2002/10/10 18:06:15  조회수:38  줄수:4
  
그럼 while(true){ ~ } 블럭안에서 입력스트림을 조사하는(입력이 있는지 여부)하는
더 좋은 방법이 있을까요? Thread.sleep()을 사용하지 않는 구조로 말입니다.

어렵게 잡은기회인데 꼭 성공하고 싶네요


제목 : Re: 참고소스
글쓴이: 신형주(shin7688)   2002/10/10 18:37:08  조회수:52  줄수:16
  
while (true) {
    try {
        if(lm_oIs.available() > 0) {
            Thread thread = new Thread() {
                public void run() {
                     // 클라이언트들에게 데이타를 보낸다.
                    sendMessage2Client(lm_oIs, client);
                }
            };
            thread.start();
        }          
    } catch(Exception e){}
}

혹시 소스를 보내 주실 생각은 없으신지요?
여기 있는 분들중에 TCP/IP 서버 만든 분들 꽤 일을거에요.


제목 : Re: 대안이 될만한 코드가 아닌거 같습니다
글쓴이: 나승민(rulu)   2002/10/10 19:09:22  조회수:46  줄수:14
  
신형주님이 올려주신 리플 코드는 문제의 소지가 있습니다.
Thread.sleep(miliseconds) 을 주지 않으면 while 구조상 무한루프를 돌기 때문에
CPU 점유가 순식간에 100%까지 올라갈것입니다.


그리고 소스의 완전공개는 개인적으로 어렵습니다.  개인적으로 만든게 아니고 회사의
제품 으로 만들고 있는거라서...(지송^.^~)


그리고 제가 첨에 제시한 코드에서 communicate()메소드 부분은 각각의 쓰레드의
run()메소드에서 호출되는 메소드입니다.
저의 경우 쓰레드는 쓰레드풀링기법을 이용하여 1000개의 쓰레드를 만들어놓고
클라이언트접속을 기다리는 구조로 되어있습니다(참고로 쓰레드풀링은 제가 직접
구현하지않고.. Allen Holub 이라는 분이 만든 걸 이용하고 있습니다.




제목 : Re: 안녕하세요 초보자인데요.. ^^;;
글쓴이: 손님(guest)   2002/10/14 19:27:07  조회수:57  줄수:16
  
토론 재미있게 보고 있습니다. 전 네트워크게임을 짜고 있는데요.
채팅도 들어가고 서버구성도 해야하기때문에.. ^^*

==================================================================================
JDK1.4에서 발표한 nio패키지를 이용하여 서버 코드를 구성한다고 할 때..
클라이언트는 애플릿을(JDK1.1.8) 쓸수 밖에 없는 구조인데.. 문제가 없는지 궁금합니다
==================================================================================

라고 하셨는데 상관 없지 않을까요?
왜냐하면 어차피 서버는 nio로 local 에서 처리하고 client 는 1.1.8 이더라고 어차피
처리는 Stream 으로 이루어 지기때문에 상관 없을거 같습니다.
해보고 말해야되는데 짐작으로 말해서 죄송합니다.

단지 토론에 살짝 참가 하고 싶어서.. ^^;;
계속 좋은 정보 주시면 감사하겠습니다. 수고 하세요



제목 : Re: socket pool 이 아니라 connection managerment pool 이겠죠.
글쓴이: 명랑폐인™(merong)   2002/10/18 21:30:51  조회수:114  줄수:26
    
보통 서버 소켓의 쓰레드에서 메소드에서 connection 요청이 올경우에
socket = sever.accept();

new ChatProcessor(sokcet).start() 형태로 많이 쓰리라 봅니다.
대부분의 책에서도 이렇게 예제를 만들어 놓구요...
그러나 채팅 프로그램을 만들어 보면, ChatProcessor에 여러가지 기능이 들어가서
class 크기가 상당히 커집니다. User class와 Room Class 를 따로 분리한더 하더라도

클라이언트에서 온 각종  메세지들을 parse 하고, 필요한 처리를 하고 db와 연결하여
작업하는 코드를 넣게 되면, 기능만큼 코드가 길어집니다. 코드가 길다는것은 class의
사이즈가 크다는 의미이고, 이것은 객체 생성에 상당한 비용이 든다는 겁니다.

socket pool이라는 의미는 socket을 pooling 하는 의미가 아닌 이 ChatPorcessor를
(runnable class가 아닐수도 있습니다만, 대부분 이렇게 처리하니까..) pool에 미리
생성해놓고 쓰자는 거겠죠..
채팅이다 보니 accept(); 가 주기적으로 생기는것이 아니라 어느때에 몰릴때도 있는데
몰리는 시간에는 접속이 상당히 느린것처럼 보이겠죠..(객체가 늦게 생성되니까.)

채팅 프로그램을 보면, 거의 모든 사용자에 대해서 처리하는 코드가 같고, 사용자에 따라
달라지는 부분은 id, name, 성별, age, email, intro, ip 정도가 되겠죠.

소켓풀이 아닌 client socket를 포함한 ChatProcessor class는 Pool 을 사용하면 성능이
많이 향상될뿐 아니라, 가용갯수를 한정함으로써 OutofMemory를 예방할수 있는 효과도
있겠죠..

그럼.
반응형