TcpMultiChatClient / TcpMultiChatServer : 다중 채팅

조수경·2021년 11월 18일
0

고급자바

목록 보기
54/97

TcpMultiChatClient

package kr.or.didt.tcp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
import java.util.Scanner;



public class TcpMultiChatClient {
	
	public void clientStart(){
		
		try {
			String serverIp = "localhost";
			
			Socket socket = new Socket(serverIp, 7777);
			System.out.println("서버에 연결되었습니다.");
			System.out.println();
			
			//메시지 전송용 쓰레드 생성
			ClientSender sender = new ClientSender(socket);
			
			//메시지 수신용 쓰레드 생성
			ClientReceiver receiver = new ClientReceiver(socket);
			
			sender.start();
			receiver.start();
			
		} catch (Exception e) {
			// TODO: handle exception
		}
		
	}  //clientStart메서드 끝...
	
	
	public static void main(String[] args) {
      new TcpMultiChatClient().clientStart();
		
		
	}

	// ---------------------------------------
	// 메시지 전송용 쓰레드
	class ClientSender extends Thread{
		private Socket socket;
		private DataInputStream dis;
		private DataOutputStream dos;
		
		private String name;
		private Scanner scan;
		
		//생성자
		public ClientSender(Socket socket){
			this.socket = socket;
			scan = new Scanner(System.in);
			
			try {
				dis=new DataInputStream(socket.getInputStream());
				dos=new DataOutputStream(socket.getOutputStream());
				
				if(dos!=null){
					//클라이언트가 처음 실행되면 자신의 대화명(이름)을 입력받아
					//서버로 전송하고 대화명의 중복여부를 feedBack으로 받아서 확인한다.
					System.out.println("대화명: ");
					String name = scan.nextLine();
					
					while(true){
					dos.writeUTF(name); //대화명 전송
					
					//피드백을 받기 위함
					String feedBack = dis.readUTF(); //대화명 중복 여부를 받는다.
					
					if("이름중복".equals(feedBack)){//대화명이 중복되면..
						System.out.println(name + "은 대화명이 중복됩니다...");
	                    System.out.println("다른 대화명을 입력하세요...");
	                    
	                    System.out.println("대화명: ");
						name = scan.nextLine();
						
					}else{
						this.name = name;
						System.out.println(name + "이름으로 대화방에 입장했습니다.");
						break; //반복문 탈충
					}
					
				  }// while문 끝...
					
				}
			} catch (Exception e) {
				// TODO: handle exception
			}
			
		}// 생성자
		
		@Override
		public void run() {
			try {
				while(dos != null){//전송용이기 때문에dos
					//키보드로 입력한 메시지를 서버로 전송한다.
					dos.writeUTF("[" + name + "]" + scan.nextLine());	
				}
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
	}
	
	//----------------------------------------------------------------
	
	// 메시지 수신용 쓰레드
	class ClientReceiver extends Thread{
		private Socket socket;
		private DataInputStream dis;
		
		//생성자
		public ClientReceiver(Socket socket) {
			this.socket = socket;
			try {
				dis = new DataInputStream(socket.getInputStream());
			} catch (Exception e) {
				// TODO: handle exception
			}
		}//생성자 끝...
		
		@Override
		public void run() {
			try {
				while(dis!=null){
					//서버가 보내온 메시지를 받아서 화면에 출력한다.
					System.out.println(dis.readUTF());
				}
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
		
	}
	
	
}

TcpMultiChatServer

package kr.or.didt.tcp;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

public class TcpMultiChatServer {
	// 접속한 클라이언트들을 저장할 Map객체 선언
	// ==> key값 : 접속한 사람의 이름, value값 : 접속한 클라이언트의 socket객체
	private Map<String, Socket> clientMap;
	
	//생성자
	public TcpMultiChatServer(){
		//clientMap을 동기화 처리: 동시에 여러사람이 접속하면 문제가 생길수 있기 때문
		//동기화는 쓰레드를 사용할때 이름이 같은 사람이 왔을때 첫번째 사람이 등록이 완료될때 까지 기다리는 개념
		clientMap = Collections.synchronizedMap(new HashMap<String, Socket>());
	}
	
	//clientMap에 저장된 전체 사용자에게 메시지를 전송하는 메서드
	private void sendToAll(String msg){
		//clientMap의 데이터 개수만큼 반복
		for (String name : clientMap.keySet()) {
			try {
				// 각 사용자의 소켓을 이용하여 OutputStream객체를 구한다.
				DataOutputStream dos = new DataOutputStream(
						clientMap.get(name).getOutputStream()  );
				//해당 소켓에 대한 아웃풋 스트림을 구함
				
				dos.writeUTF(msg);
				
			} catch (Exception e) {
				// TODO: handle exception
			}
		}
		
	}
	
	public void serverStart(){
		ServerSocket server = null;
		Socket socket = null;
		
		try {
			server = new ServerSocket(7777);
			System.out.println("서버가 시작되었습니다...");
			while(true){
			   socket = server.accept(); //클라이언트의 접속을 기다린다.
			  
			   System.out.println("[" + socket.getInetAddress() + " : " 
		                + socket.getPort() + "]에서 접속을 했습니다...");
			   
			   // 메시지를 받아서 전체에게 전송하는 Thread객체를 생성하여 작동시킨다.
			   ServerReceiver serverThread = new ServerReceiver(socket);
			   serverThread.start();
			
			}
			
			
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			if(server != null) 
				
				try {
				server.close();
			} catch (Exception e2) {
				
			}
		}
		
	}

	public static void main(String[] args) {
       new TcpMultiChatServer().serverStart();
	}

	// Inner Class로 서버에서 클라이언트로 메시지를 전송하는  Thread를 만든다.
	class ServerReceiver extends Thread{
		private Socket socket;
		private DataInputStream dis;
		private DataOutputStream dos;
		
		//생성자
		public ServerReceiver(Socket socket) {
			this.socket = socket;
			
			try {
				//수신용 객체 생성
				 dis = new DataInputStream(socket.getInputStream());
				 
				 //송신용 객체 생성
				 dos = new DataOutputStream(socket.getOutputStream());
				 
			} catch (Exception e) {
				// TODO: handle exception
			}
			
		}//생성자 끝...
		
		@Override
		public void run() {
			//이름을 받아서 클라이언트 맵에 같은 이름이 있는 경우
			//중복 여부를 클라이언트에게 보내고 (클라이언트는)새로운이름으로 등록하는 작업
			
			String name = ""; //이름 저장 변수
			try {
				while(true){
					//클라이언트가 접속이 완료되면 최초로 사용자의 이름을 전송하는데
					//이 이름이 중복되는지 여부를 feedBack으로 클라이언트에게 보내준다.
					name = dis.readUTF();
					
					if(clientMap.containsKey(name)){ //이름이 중복될때...
						dos.writeUTF("이름중복");
					}else{//이름이 중복되지 않을때...
						dos.writeUTF("OK");
						break; //반복문 탈출
					}
				}//while문 끝...
				
				// 현재 접속해 있는 다른 클라이언트들에게 대화명(이름)을 이용해서
				// 대화방 참여 메시지를 보낸다.
				sendToAll("[" + name + "]님이 대화방에 입장했습니다...");
				
			    // 대화명과 클라이언트의 Socket객체를 Map에 저장한다.
				clientMap.put(name, socket);
				
				System.out.println("현재 서버 접속자 수 : " 
				             + clientMap.size() + "명");
			
				// 한 클라이언트가 보낸 메시지를 다른 클라이언트에게 전송해 준다.
				while(dis != null){
					sendToAll(dis.readUTF());//사용자에게 받아서 전체에게 보내준다.
				}
				
				
			} catch (Exception e) {
				// TODO: handle exception
			} finally{
				// 이 finally영역이 실행된다는 것은 
				// 클라이언트가 접속을 종료했다는 의미이다.
				
				// 사용자 목록에서 해당 클라이언트를 삭제한다.
				clientMap.remove(name);
				
				// 다른 사용자에게 대화방을 나갔다는 메시지 전송
				sendToAll("[" + name + "]님이 대화방을 나갔습니다...");
				
				System.out.println("[" + socket.getInetAddress() + " : " 
				                + socket.getPort() + "]에서 접속을 종료했습니다...");
				
				System.out.println("현재 서버 접속자 수 : " 
			             + clientMap.size() + "명");
				
			}
			
		}
	}
	
}
profile
신입 개발자 입니다!!!

0개의 댓글

관련 채용 정보