개인참고자료/자바(네트워크)

TCP 프로그래밍 - 멀티스레드를 이용한 에코 서버

경진 2008. 7. 17. 23:46
멀티스레드를 이용한 에코 서버

서버가 클라이언트 여러 개를 동시에 처리하지 못하는 점을 해결하는 몇가지 방법이 있다.
그 중 한 가지 방법인 스레드를 이용한 방법을 사용한다.

서버는 연결된 클라이언트의 수만큼 소켓을 가지게 되는데, 각각의 소켓은 각각 별개로 동작해야 한다.

서버는 accept()로 대기하고 있다가 클라이언트가 접속하게되면 socket 객체를 반환하게 된다. 반환 받은 소켓은 스레드의 생성자에 전달된다. 그리고나서 스레드 객체를 시작하고 다시 메인 스레드는 accept()로 대기하게 된다.

실제로 클라이언트와 통신을 하는 것은 스레드 객체의 run() 메소드 안에서 일어난다.

멀티스레드 에코 서버의 동작 순서

멀티스레드 에코 서버의 동작 순서

멀티스레드 에코 서버 프로그래밍

import java.net.*;               
import java.io.*;                
               
public class EchoThreadServer {                
               
    public static void main(String[] args) {           
        try{       
            ServerSocket server = new ServerSocket(10001);   
            System.out.println("접속을 기다립니다.");   
            while(true){   
                Socket sock = server.accept();
                EchoThread echothread = new EchoThread(sock);
                echothread.start();
            } // while   
        }catch(Exception e){       
            System.out.println(e);   
        }   
    } // main       
}            
           
class EchoThread extends Thread{           
    private Socket sock;       
    public EchoThread(Socket sock){       
        this.sock = sock;   
    } // 생성자       
    public void run(){       
        try{   
            InetAddress inetaddr = sock.getInetAddress();
            System.out.println(inetaddr.getHostAddress() + " 로 부터 접속하였습니다.");
            OutputStream out = sock.getOutputStream();
            InputStream in = sock.getInputStream();
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
            BufferedReader br = new BufferedReader(new InputStreamReader(in));   
            String line = null;   
            while((line = br.readLine()) != null){   
                System.out.println("클라이언트로 부터 전송받은 문자열 : " + line);
                pw.println(line);
                pw.flush();
            }   
            pw.close();   
            br.close();   
            sock.close();   
        }catch(Exception ex){       
            System.out.println(ex);   
        }       
    } // run           
}               

서버 소켓을 생성한 후 무한히 반복하는 while문 안에서 accept() 메소드를 실행해서 클라이언트를 대기 시킨다. 클라이언트가 접속하게 되면 accept() 메소드는 접속한 클라이언트의 소켓 객체를 반환하게 된다.
반환 받은 소켓 객체는 스레드 객체인 EchoThread의 생성자에 인자로 지정한다. EchoThread의 생성자로 소켓 객체를 지정함으로써 EchoThread가 접속한 클라이언트와 통신을 할 수 있게 한다.

            ServerSocket server = new ServerSocket(10001);   
            System.out.println("접속을 기다립니다.");   
            while(true){   
                Socket sock = server.accept();
                EchoThread echothread = new EchoThread(sock);
                echothread.start();
            } // while 

EchoThread는 Thread 객체로서 Thread를 상속받고 있다. 그리고 스레드 생성자의 인자에 소켓 객체를 전달하게 함으로써 외부에서 생성된 소켓으로 통신할 수 있게 한다.

class EchoThread extends Thread{           
    private Socket sock;       
    public EchoThread(Socket sock){       
        this.sock = sock;   
    } // 생성자     

EchoThread의 run() 메소드는 실제로 클라이언트와 통신하는 방식을 구현하고 있는 부분이다. EchoServer와 구현된 내용은 같다. 메인스레드에서 소켓 객체를 생성한 후 EchoThread에게 어떻게 전달해서 run 메소드에 통신할 수 있게 했는지에 대한 부분이다.

            OutputStream out = sock.getOutputStream();
            InputStream in = sock.getInputStream();
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
            BufferedReader br = new BufferedReader(new InputStreamReader(in));   
            String line = null;   
            while((line = br.readLine()) != null){   
                System.out.println("클라이언트로 부터 전송받은 문자열 : " + line);
                pw.println(line);
                pw.flush();
            }   

멀티스레드 에코 서버 실행

멀티스레드 에코 서버의 소스를 작성했으면 컴파일한 후 실행한다. 그리고 새로운 도스창을 두개 열고 실행하면 각각의 클라이언트에 서버에게 전달한 문자열이 제대로 전달되는지 확인할 수 있다.