본문 바로가기
JAVA SE/Code

CODE [20.08.05/Day_20] Java SE / Network 네트워크 | 다수의 클라이언트에서 메아리 서비스 구현 (멀티 스레드 활용)

by 파프리카_ 2020. 8. 5.
728x90
반응형

step4   다수의 클라이언트에게 지속적으로 메아리 서비스하는 서버 구축

 

 

다수의 클라이언트에게 지속적으로 서비스하기 위해서는 서버측에 멀티 스레드가 필요하다. 

클라이언트가 접속할 때, 서버는 접속한 클라이언트에 대응되는 소켓을 accept()으로 반환받고,

클라이언트와 실제 통신할 ServerWorker Thread 생성 시에 생성자에 해당 소켓을 할당한다.

이렇게 ServerWorker Thread를 생성하고, start() 하는 역할까지가 MultiServer의 할일이다.

⇒ ServerWorker는 MultiServer내 while문에 삽입되어 작동하는 역할을 한다.

 


[ 클라이언트 측 필요 클래스 ] 

클라이언트는 step3의 Client를 그대로 사용해도 된다.

(https://creamilk88.tistory.com/47)

 


[ 서버 측 필요 클래스 ]

Multi Server

:  1 대 다, 즉 다수의 클라이언트에게 지속적으로 메아리 서비스하는 서버

package step4;
/*
 * 1 대 다, 즉 다수의 클라이언트에게 지속적으로 메아리 서비스하는 서버
 */

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;


public class MultiServer {
	/*
	 * ServerSocket 생성 
	 * while loop 
	 * accept() : Socket을 통해 접속 대기 접속하면 
	 * client의 Socket 반환됨 
	 * ServerWorker Thread를 생성할 때, 
	 * 생성자에 해당 Socket을 할당 start() 를 이용해 
	 * 해당 스레드를 실행가능상태로 보낸다.
	 */
	private void go() throws IOException {
		ServerSocket serverSocket = null;
		Socket socket = null;

		try {
			//서버 소캣 생성
			serverSocket = new ServerSocket(5432);
			System.out.println("step 4 멀티 서버실행 - 클라이언트 접속 대기 중\n");

			while(true) 
			{
			/*다수의 클라이언트에게 서비스해야 하기 때문에, 반복문 수행
			* 다수의 클라이언트 - 그에 따라 반환되는 Socket
			* 클라이언트 접속 시, 일반 Socket 반환 - 직원 Thread
			*/
			socket = serverSocket.accept();
			System.out.println(socket.getInetAddress() + " 님이 접속했습니다");
			
			// 실제 클라이언트와 통신할 객체 생성 시에 소켓을 할당한다.
			//상담원 객체를 만들어서 전화기를 준다
			ServerWorker serverworker = new ServerWorker(socket);
			
			// mainThread와 별개로 실행됨
			Thread threadWorker = new Thread(serverworker);
			threadWorker.start();
			
			}	
		} finally {
			if (socket != null)
				socket.close();
			if (serverSocket != null)
				serverSocket.close();
		}
	} // go method

	public static void main(String[] args) {
		try {
			new MultiServer().go();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
	}//main method

}

 

Server Worker (implements Runnable)

: 개별 클라이언트와 메세지를 받고 줄 Thread 객체 -> MultiServer에 호출되어 실행될 것임

생성자로부터 할당받은 socket을 이용해, 클라이언트와 통신을 하면 된다.

→ 클라이언트 메세지를 입력받아 콘솔에 출력하고, 다시 클라이언트로 그 메세지를 출력하는 일을 반복

package step4;
/*
 * 개별 클라이언트와 메세지를 받고 줄 Thread 객체
 */
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class ServerWorker implements Runnable {
	private Socket socket;
	
	public ServerWorker(Socket socket) {
		super();
		this.socket = socket;
	}
	
	@Override
	public void run() {
		try 
		{
			echo();
		} 
		
		catch (IOException e) 
		{
			e.printStackTrace();
		} 
		
		finally 
		{
			if (socket != null) 
			{
				try 
				{
					socket.close();
				} 
				catch (IOException e) 
				{
					e.printStackTrace();
				}
			}
		}
	}

	/*
	 * 접속한 클라이언트와 지속적으로 통신
	 * 입력받아 다시 출력하고 종료메세지가 오면
	 * close() 작업 수행 후, run()메서드 종료 - 스레드 종료
	 */
	public void echo() throws IOException {
		
		//입력받는 node stream 
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			
		//출력하는 node stream
		PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
		
		//서버에 접속하는 Client 주소
		String user = socket.getInetAddress().toString();
		
		//입력과 출력 반복 - processing stream
		while(true)
		{
			try {
			// Client에서 입력 받은 메세지 읽기
			String message = br.readLine();
			
			// message에 "종료" or null이 들어오면 종료
			if (message == null | message.equals("null") |
					message.trim().equals("종료"))
			{
				System.out.println("**" + user + "님이 접속을 종료했습니다**");
				break;
			}
			// 콘솔창에 받은 메세지 보여주기
			System.out.println(user +" 님이 입력한 메세지 :" + message);
			
			// Client에 메세지 바로바로 출력하기
			pw.println(message + " *server*");
			} //try-while
			
			// Client에서 if 조건 외의 방법으로 접속을 끊을 경우
			catch(Exception e) {
				System.out.println("**"+ user+"님이 접속을 종료했습니다");
				break;
			}//catch-while
		}//while
			
	}//echo method
}

 


 

MultiServer Console 결과 

 

TestClient Console 입출력 결과 1

 

TestClient Console 입출력 결과 2

728x90
반응형