본문 바로가기
CLASS/JAVA

#18-2 / Thread를 이용한 멀티 서버

by hingu 2024. 5. 27.
⚡ TCP 멀티서버
public class multi_server {
	public static void main(String[] args) {
		new server_port();
	}
}

//멀티 포트 설정
class server_port {
    /* 
    -싱글포트로 한다면?
    int port = 9001;
    server_open so = new server_open(port); //배열의 포트번호
    so.start();
    */
    
    /*멀티포트*/
	public server_port() {
		int port[] = {9001,9002,9003}; //원시배열 사용 - 해당 포트를 다 열어버리겠다
		int w=0;
		while(w<port.length) {
			server_open so = new server_open(port[w]); //배열의 포트번호
			so.start(); //thread 클래스의 run 메소드 실행 - 스레드 발동
			
			w++;
		}
	}
}

//멀티 포트 open (Thread 이용)
class server_open extends Thread{ //멀티 스레드
	String ip = "";
	int pt = 0;
	ServerSocket sk = null;
	Scanner sc = null;
	
	public server_open(int p) { //즉시실행
		this.ip = "172.30.1.83";
		this.pt = p;
	}
	
	@Override
	public void run() { //실행
		try {
			this.sk = new ServerSocket(this.pt); //socket을 이요하여 포트 오픈
			while(true) { 
				Socket s = this.sk.accept(); //client가 접속을 할 수 있도록 반복문으로 대기
				System.out.println(this.pt + "서버 오픈");
			}
		}catch(Exception e) {
			System.out.println("중복된 port로 인하여 서버가 실행되지 않습니다");
		}
	}
}

 

⚡ Thread를 이용한 client
public class multi_client {
	public static void main(String[] args) {
		new client_port();

	}
}

class client_port {
	Socket sk = null;
	String serverip = "";
	int port = 0;
	public client_port() {
		this.serverip = "172.30.1.83";
		this.port = 9001;
		try {
			this.sk = new Socket(this.serverip,this.port);//port번호 선택 - 톡 방 선택
			System.out.println("서버 접속 완료!!");
			
			Thread co = new client_open(); //Thread 메소드 호출
			co.start(); //thread 클래스의 run 메소드 실행 - 스레드 발동
			
		}catch(Exception e) {
			System.out.println("서버 접속 오류 발생!!");
		}
	}
}

//채팅에 참여했을 때 같은 port 사용자끼리 대화시 사용되는 부분
class client_open extends Thread{
	public client_open() {
		
	}
	
	@Override
	public void run() {
		
	}
}

 

🌺 채팅방 만들기
송신파트,수신파트 Thread로 분리


PrintWriter : stream -> writer 자동변환 시켜줌(byte -> String)

[server]
System.out.println(this.socket.getInetAddress()); - 상대방 접속ip 출력System.out.println(this.socket.getKeepAlive()); - socket 유무 메소드(true,false)
System.out.println(this.socket.getPort()); - 접속 port 출력


⚡ server
public class net_chat_server {
	public static void main(String[] args) {
		new net_chat_server().open();
	}
	
	//소켓을 유지하는 스레드
	public void open() {
		ServerSocket ss = null;
		Socket sk = null;
		try { 
			ss = new ServerSocket(9000);
			System.out.println("[*-*-채팅 서버 오픈-*-*]");
			while(true) { //socket을 유지하기 위한 무한반복문
				sk = ss.accept(); //유지
				chatroom ch = new chatroom(sk); //Thread
				ch.start(); //Thread 작동
			}
		}catch(Exception e) {
			System.out.println("서버 포트 충돌로 인하여 서버 가동을 중지합니다");
		}finally {
			if(ss != null) {
				try {
					ss.close();
					System.out.println("서버를 강제 종료 합니다");
				}catch(Exception e) {
					System.out.println("서버 소켓이 완전 오류가 발생함");
					System.exit(0);
				}
			}
		}
	}	
}

//관리자가 직접 채팅 사용 가능(관리자 Scanner 가능)한 기능으로 제작시 별도의 Thread로 빼야함
//송수신역할을 하는 Tread 클래스
class chatroom extends Thread {
	InputStream is = null;
	InputStreamReader isr = null;
	BufferedReader br = null;
	OutputStream os = null;
	Socket socket = null;
	PrintWriter pw = null; //stream -> writer 자동변환 시켜줌(byte -> String)
	String mid = ""; 
	
	//서버에 접속한 모든 사용자 리스트 메모리에 저장 
	static List<PrintWriter> list = new ArrayList<PrintWriter>();
	
	public void message(String msg) { //배열에 있는 모든 사용자에게 동일한 메세지 전달
		for(PrintWriter pw : this.list) {
			pw.println(msg); //발송
			pw.flush(); //메모리 내용을 비움
		}
	}
	
	@Override
	public void run() {
		try {
			this.mid = this.br.readLine();
			String hello = "[ "+ this.mid +" ] 님이 입장했습니다.";
			System.out.println(hello);
			this.message(hello);
			
			while(this.br != null) { //메세지를 입력하면 작동이 되는 반복문
				hello = this.br.readLine().intern();
				if(hello == "나가기") {
					break;				
				}else {
					this.message(this.mid +":" + hello);
				}
			}
		}catch(Exception e) {
			System.out.println("사용자 추가 오류 발생으로 접속이 해제됩니다");
		}finally {
			this.message(this.mid + "님이 퇴장했습니다.");
			this.list.remove(this.pw);
			try {
				this.socket.close();
			}catch(Exception e) {
				System.out.println("--채팅 서버 종료--");
			}
			System.out.println(this.mid + "님 퇴장ㅎ");
		}
	}
	
	public chatroom(Socket s) {
		this.socket = s;
		try {
			//접속에 대한 정보를 list배열에 추가
			this.pw = new PrintWriter(this.socket.getOutputStream());
			this.list.add(this.pw);
			System.out.println("채팅 참여자 : 총" + this.list.size() + "입니다");
			
			//채팅 관련 정보
			this.is = this.socket.getInputStream();
			this.isr = new InputStreamReader(this.is);
			this.br = new BufferedReader(this.isr);
			
			System.out.println(this.socket.getInetAddress()); //상대방 접속 ip
		}catch(Exception e) {
			System.out.println("소켓 통신 오류 발생!!!");
		}
	}
}



⚡ client

public class net_chat_client {
	public static void main(String[] args) {
		new net_chat_client().open();
	}
	public void open() {
		String ip = "172.30.1.5";
		int port = 9000;
		try {
			//딱 한번만 작동 나머지는 thread로 작동
			Socket sk = new Socket(ip,port);
			System.out.println("[** 채팅서버 접속 완료 **]");
			Scanner sc = new Scanner(System.in);
			System.out.println("생성할 id를 입력하세요 : ");
			String mid = sc.nextLine();
			
			//Tread로 값을 이관(서버에 메세지를 송수신) - 보내는 내용을 Thread로 추가
			Thread th = new chat_clients(sk,mid);
			th.start(); //새로운 작업공간이 열림
			
			//접속 입장시 상대방에 대한 메세지를 출력(서버쪽 내용을 출력)
			InputStream is = sk.getInputStream();
			InputStreamReader isr = new InputStreamReader(is);

			//BufferedReader 사용시
			  //null이 아닐 경우 송수신에 대한 byte 메모리가 full이 되므로 값이 전달 안됨
			BufferedReader br = new BufferedReader(isr);
			
			//수신
			while(br != null) {
				String chat_msg = br.readLine();
				//서버에서 보내준 내용과 동일할경우 종료
				if(chat_msg.equals(mid+"님이 퇴장하셨습니다")) {
					System.out.println("채팅 프로그램 종료");
					System.exit(0); //강제 종료
					break;
				}
				//자신의 화면에 서버 메세지를 출력하는 역할
				System.out.println(chat_msg);
			}
			sc.close();
			sk.close();
			
		}catch(Exception e) {
			System.out.println("소켓통신 서버 접근 오류!!");
		}	
	}
}

//송신 역할을 하는 Thread (수신은 x)
class chat_clients extends Thread{
	Socket sk = null;
	String mid = null;
	Scanner sc = null;
	
	public chat_clients(Socket s, String id) {
		this.sk = s;
		this.mid = id;
		this.sc = new Scanner(System.in);
	}
	
	@Override
	public void run() {
		try {
			//접속 id를 전송(첫번째 메세지)
			PrintStream ps = new PrintStream(this.sk.getOutputStream());
			ps.println(this.mid);
			ps.flush();
			
			//사용자가 입력하는 메세지를 서버로 전송
			while(true) {
				System.out.println("채팅 메세지를 입력하세요");
				String msg = this.sc.nextLine();
				ps.println(msg);
				ps.flush();
			}
			
		}catch(Exception e) {
			System.out.println("서버 소켓 오류 발생으로 채팅이 중지됩니다.");
		}
	}
}

 

 

'CLASS > JAVA' 카테고리의 다른 글

#20-1 / 람다(lamda)코드 사용 방식  (1) 2024.06.11
#19 / Thread (class 형태 , interface 형태)  (0) 2024.05.31
#18-1 / 서버 - UDP  (0) 2024.05.27
#17 / remind3  (0) 2024.05.24
#16-2 / 서버 - TCP  (0) 2024.05.23