'자바배우기'에 해당되는 글 67건

  1. 2008.03.28 Socket-8.Concurrent TCP 네트워크 서버

Concurrent TCP 네트워크 서버

 

예제 11 - 7 IterativeServer와 예제 11 - 8 Fan은 대표적인 TCP 네트워크 기반의

서버와 클라이언트의 구조이기는 합니다만 결정적인 단점이 있습니다.

IterativeServer의 스타 인사말 서비스 객체가 존재하는 반복문(while)안을 살펴보면

새로 만들어지는 Thread가 없습니다. , IterativeServer는 실제 일을 하는 Main Thread

하나 만으로 서비스를 제공합니다.

반복문 안에 있는 서비스 객체를 계속 수행하면서 클라이언트에게 서비스를 제공하고

있지만 클라이언트 A에게 인사말 서비스를 제공하고 있을 동안에는 클라이언트 B에게

인사말 서비스를 제공할 수 없습니다. 반복문의 구조를 보면 한 개의 Thread로는

클라이언트 B에게 인사말 서비스를 제공할 방법이 없습니다.

IterativeServer의 한계는 특정한 시간에 하나의 클라이언트 밖에 서비스를 하지 못합니다.

그 가장 큰 이유는 서비스를 제공하는 Thread Main Thread 단 하나이기 때문입니다.

 

만약 IterativeServer가 동시에 여러 개의 클라이언트에게 스타 인사말 서비스를 제공하려고

한다면 서비스를 수행하는 Thread를 여러 개 만들면 문제를 해결할 수 있습니다.

한 개의 Thread가 하나의 클라이언트를 위해서 일을 하면 되니까 간명한 이치이지요.

이와 같이 여러 개의 클라이언트를 동시에 서비스할 수 있는 서버를 Concurrent 서버라고

합니다.  Concurrent 서버의 핵심은 클라이언트 하나당 Thread를 생성하고, Thread에게

서비스를 맡기는 겁니다.

 

Concurrent 서버의 기본적인 구조는 이원화 되어 있습니다.

ServerSocket을 만들고,클라이언트로부터 TCP 연결을 기다리는 일은 반복문 밖에서 Main

Thread가 하고, 반복문 안에서 일단 클라이언트로부터 TCP 연결이 이루어진후에는

클라이언트를 위해 일할 Thread를 만들고, Socket객체와 서비스 객체를 만들어낸 Thread

하여금 일 하도록 하는 겁니다.

 

여러분들도 잘 아시다시피 일단 Thread가 만들어지면 없어서는 안될 것이 Runnable 객체

입니다. Concurrent 서버의 입장에서 Runnable객체는 바로 서버가 제공하는 서비스 객체를

의미합니다. Concurrent 서버의 구현은 일꾼 Thread와 서비스 객체 Runnable의 활용에

달려있습니다.

 

이제는 IterativeServer ConcurrentServer로 서버로 업그레이드 시켜 보겠습니다.

 

Runnable 서비스 객체

 

ConcurrentServer에서 없어서는 안될 Runnable 서비스 객체를 만들겠습니다.

Runnable 객체는 반드시 public void run() 메소드를 구현해야만 합니다.

당연한 얘기이지만 그러면서도 서비스를 구현해야겠지요.

여기서는 기존에 존재하는 Star 서비스 객체를 상속을 통해서 Runnable 객체로 바꿔

보겠습니다.

 

package tcp;                                                                                                                               

 

import java.io.*;

import java.net.*;

import java.util.*;

 

 

/**

* Socket InputStream으로 스타의 이름을 받으면, Socket OutputStream으로 

* 스타의 인사말을 보내줍니다.

* Star는 스타 이름과 스타의 인사말을 Map에 등록합니다.

* Runnable 객체입니다.

*/

public class StarTask extends Star implements Runnable {

            

             public StarTask(Socket s) {

                           super(s);            

             }

            

             public void run()  {           

                           /* 스타인사말 서비스 객체의 서비스를 제공합니다.*/

                           super.hello();

             }

}           

예제 11 - 9 StarTask.java

 

StarTask는 기존 서비스 객체인 Star를 상속해서 Star가 제공하는 모든 기능을 갖고

있습니다. 그리고 Thread와 함께 사용할 수 있도록 Runnable 객체로 설계했습니다.

Thread가 실행하는 메소드인 public void run()에는 서비스 객체인 Star hello()메소드를

수행하도록 구성했습니다. StarTask Star를 상속했으므로 super.hello() Star객체의

hello()메소드를 실행하는 것이지요.

필자는 Runnable객체는 클래스이름에 항상 Task를 붙여서 구별합니다.

 

이제 Runnable서비스 객체인 StarTask를 이용하는 ConcurrentServer를 구성하겠습니다.

 

package tcp;                                                                                                                                            

 

import java.io.*;

import java.net.*;

import java.util.*;

 

/**

* TCP 네트워크 클라이언트에게 스타의 인사말 서비스를 제공합니다.

*/

public class ConcurrentServer {

 

             /**

             * 클라이언트가 TCP 포트 8989 Listen하면서 TCP 연결을 한후,

             * 스타의 인사말을 요청하면 해당 스타의 인사말을 보내줍니다.

             */

             public static void main(String[] args) {

                           try {

                                        ServerSocket ss = new ServerSocket(8989);    

 

                                        /* 서비스 중지하지 않고 계속 서비스 합니다.

                                           서비스를 하는 서버가 다중 Thread이므로 여러 클라이언트가

               동시에 서비스를 요청하더라도 모든 클라이어트를 동시에 서비스 합니다.*/

             

                                        while (true) {

                                                     Socket s = ss.accept();                                                           

                                                     Runnable task = new StarTask(s);                 

                                                     new Thread(task).start();                                           

                                        }

                           }

                           catch(IOException io) {

                                        io.printStackTrace();

                           }

             }

}

예제 11 - 10 ConcurrentServer.java

 

ConcurrentServer public static void main(String[])에서는 Main Thread가 반복문

바깥에서 ServerSocket을 만들고, 반복문 안에서 서비스 객체와 서비스 객체를 서비스할

Thread를 만듭니다.

, 클라이언트가 TCP 연결 해오기를 줄창 기다리다고, 드디어 TCP 연결을 해오면 Socket

객체와 서비스 객체를 만들어내는 것은 Main Thread가 담당을 합니다.

일단 Socket 객체와 서비스 객체가 만들어지면 서비스 객체를 이용해서 서비스를 제공하는

것은 새롭게 만든 Thread로 하여금 하게하고, MainThread는 또다시 새로운 클라이언트로

부터 TCP 연결이 올 때 까지 줄창 기다립니다.

대분분의 Concurrent 서버는 이같은 구조를 가집니다.  꼼꼼히 살펴 이해하기 바랍니다.

 

ConcurrentServer IterativeServer와 꼭 같은 기능을 하면서 동시에 여러 개의 클라이언트

에게 스타인사말 서비스를 제공할 수 있는 능력을 갖게 되었습니다.

일반적으로 TCP 서버 모델은  ConcurrentServer와 매우 유사합니다.


사용자 삽입 이미지
 

그림 11 - 10

 

그림 11 - 10 tcp.ConcurrentServer를 실행한 모습입니다.

tcp.Fan 을 실행시키면 스타의 인사말 서비스를 받을 수 있습니다.

Posted by
,