2020.11.09 TcpMulti 고급자바 수업노트

 TcpMultiChatClient



package kr.or.ddit.tcp;


import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.net.Socket;

import java.util.Scanner;


public class TcpMultiChatClient {


public static void main(String[] args) {

new TcpMultiChatClient().clientStart();


}


// 클라이언트 시작 메서드

private void clientStart() {

Socket socket = null;


try {

String serverIp = "localhost";

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

}


}// 클라이언트 시작 메서드 끝


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 문의 끝


} // if 문 끝


} catch (Exception e) {

// TODO: handle exception


} // CATCH 끝


} // 생성자의 끝


@Override

public void run() {

try {

while (dos != null) {

// 키보드로 입력한 메시지를 서버로 전송한다.

dos.writeUTF("[" + name + "] " + scan.nextLine());

}

} catch (Exception e) {

// TODO: handle exception

}

} // run()메서드 끝..


} // 전송용 쓰레드 끝...


// 메시지 수신용 쓰레드

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

}

}


} // 메소드 ClientSend 끝


}



TcpMultiChatServer 



package kr.or.ddit.tcp;

import java.awt.TrayIcon;
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 값 : 클라이언트와 접속된 소켓 객체 
private Map<String, Socket> clientMap; 

//생성자
public TcpMultiChatServer() {
//clientMap을 동기화 처리가 되도록 생성한다.  
clientMap = Collections.synchronizedMap(new HashMap<String, Socket>());  
}// 생성자 끝 ..

public static void main(String[] args) {
// TODO Auto-generated method stub
new TcpMultiChatServer().serverStart();
}

//서버 시작 메서드 
private 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() + "]에서 접속했습니다.");
//서버용 쓰레드 시작하기 
ServerThread serverThread = new ServerThread(socket);
serverThread.start();
}
} catch (Exception e) {
// TODO: handle exception
} finally {
if(server != null) try {server.close();} catch(Exception e ){}
}
} //서버 시작 메서드 끝 
//clientMap 에 저장된 전체 사용자에게 메세지를 전송하는 메서드 
private void sendToAll(String msg) {
//clientMap 의 데이터 개수만큼 반복하기
for(String name : clientMap.keySet()) {
try {
DataOutputStream dos = new DataOutputStream (
clientMap.get(name).getOutputStream() // 클라이언트와 연결되어 있는 소켓의 OutputStream 객체 구하기 
);
dos.writeUTF(msg); 
} catch (Exception e) {
// TODO: handle exception
}
}
}//sendToAll 메서드 끝
//클라이언트와 연결된 소켓을 이용하여 하나의 클라이언트가 보내온 메시지를 다른 클라이언트들에게 전송하는 Thread를 inner Class형태로 만든다  
class ServerThread extends Thread{
private Socket socket; 
private DataInputStream dis; 
private DataOutputStream dos ;
//생성자 생성 
public ServerThread(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 {
//클라이언트가 보낸 첫번째 데이터는 사용자의 이름인데 
// 이 이름이 중복되는지 여뷰를 feedback 으로 클라이언트에게 보내주고 
// 이름이 중복되지 않으면 반복문을 탈출한다. 
while(true) {
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 영역이 실행된다는 것은 클라이언트가 접속을 종료했다는 의미; 
sendToAll("[" + name + "]" + "님이 접속을 종료했습니다."); 
//접속을 종료한 클라이언트를 Map 에서 삭제한다. 
clientMap.remove(name); 
System.out.println("[" + socket.getInetAddress() + "]" + socket.getPort() + "]에서 접속을 종료했습니다.");
System.out.println("현재 서버 접속자 수 : " + clientMap.size() + "명");
}
}
}

}





댓글