import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.net.Socket;

import java.net.UnknownHostException;

import java.util.Scanner;


public class ChatClient {

public static void main(String[] args) {

try {

String serverIp = "127.0.0.1";

Socket chSocket = new Socket(serverIp, 7777);

Socket fiSocket = new Socket(serverIp, 7778);

System.out.println("서버에 연결되었습니다");


new Thread(new ClientSender(chSocket)).start();

new Thread(new ClientReceiver(chSocket, "receive.txt")).start();

} catch (UnknownHostException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}


static class ClientSender extends Thread {

Socket socket;

DataOutputStream out;


ClientSender(Socket socket) {

try {

out = new DataOutputStream(socket.getOutputStream());

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}


public void run() {

Scanner sc = new Scanner(System.in);

try {

while (out != null) {

out.writeUTF(sc.nextLine());

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}


static class ClientReceiver extends Thread {

Socket fiSocket;

DataInputStream in;

String file;

ClientReceiver(Socket socket, Socket fiSocket, String file) {

this.fiSocket = fiSocket;

this.file = file;

try {

in = new DataInputStream(socket.getInputStream());

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}


public void run() {

while (in != null) {

try {

String readLine = in.readUTF();

System.out.println(in.readUTF());

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

}




static class ClientFileReceiver extends Thread {


DataInputStream in;

FileOutputStream out;

byte[] b = new byte[1024 * 4];


ClientFileReceiver(Socket fileSocket, String file) {

try {

in = new DataInputStream(fileSocket.getInputStream()); // 클라이언트가 보낸 파일을 받는다

out = new FileOutputStream(file); // 그걸 저장

} catch (Exception e) {

e.printStackTrace();

}

}


public void run() {

try {

int len = 0;

int total = 0;

while ((len = in.read(b, 0, b.length)) != -1) {

out.write(b, 0, len);

total += len;

}

out.close();

System.out.println("receiver : " + total + "bytes received");

} catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

} // run

}


///////////////////////////////  여기까진 클라이언트 클래스


//////////////////////////////// 여기부턴 서버 클래스 

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.net.ServerSocket;

import java.net.Socket;

import java.util.ArrayList;

import java.util.Collections;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;


/*

 *  2개 이상의 클라이언트에게 채팅 서비스를 제공 // 완료

 *  파일 전송 서비스도 제공 // 아직 못함

 *  대화방을 제공 // map(대화방)을 map(리스트)에 담는다 // 완료

 *  

 *  클라이언트가 접속하면, 

 *   현재 대화방 리스트를 보여주고, // 완료

 *       >클라이언트가 선택한 대화방으로 조인시킨다. // 완료

 *      >새로운 대화방을 만듦 // 완료

 *   

 *   대화방

 *    사용자간의 대화는 모든 참여 사람들에게 전송 // 완료

 *    파일 전송도 모든 사람들에게 전송 // 아직 못함

 *   

 *   옵션

 *     비밀 대화방 // 완료

 *     방장이 자기방만 대화방 폐쇄 // /방폭하기

 *     방장이 특정 클라이언트 퇴출 // /강퇴하기

 *     방장이 비번 변경 // 비번 변경하기 /강퇴하기

 */

public class ChatServer {

// <방제/ 비번, 대화방>, 사이즈는 대화방 개수

HashMap<ArrayList<String>, HashMap<ArrayList, DataOutputStream>> chatRoom = null;


// 대화방 <이름 / 방장 여부, 클라이언트에게 쏴줄 아웃풋>, 사이즈는 그 대화방에 접속한 사람수

HashMap<ArrayList, DataOutputStream> clients = null;


ChatServer() {

chatRoom = new HashMap<>();

Collections.synchronizedMap(chatRoom);

}


public void start() {

ServerSocket chatSocket = null;

ServerSocket fileSocket = null;

Socket chSocket = null;

Socket fiSocket = null;


try {

chatSocket = new ServerSocket(7777); // 대화 소켓은 7777

fileSocket = new ServerSocket(7778); // 파일 소켓은 7778

System.out.println("서버가 시작되었습니다.");


while (true) {

chSocket = chatSocket.accept(); // 대화 연결 기다림

fiSocket = fileSocket.accept(); // 파일 연결 기다림

System.out.println("[" + chSocket.getInetAddress() + ":" + chSocket.getPort() + "] 에서 접속하였습니다.");

ServerReceiver thread = new ServerReceiver(chSocket, fiSocket);

thread.start();

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

void sendFileToAll (ArrayList roomSetting, String file, String name, DataOutputStream out) {

try {

DataInputStream in = new DataInputStream(new FileInputStream(file));

DataOutputStream out2;

byte[] b = new byte[1024 * 4];

Iterator it = chatRoom.get(roomSetting).keySet().iterator();

while (it.hasNext()) {

out2 = (DataOutputStream) chatRoom.get(roomSetting).get(it.next());

int len = 0;

int total = 0;

while ((len = in.read(b, 0, b.length)) != -1) {

out2.write(b, 0, len);

total += len;

}

out2.close();

System.out.println(name +"님이 " + total + "bytes 크기의 파일 " + file +"을 보냈습니다");

}

} catch (FileNotFoundException e1) {

try {

out.writeUTF("해당 파일이 없습니다");

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

void sendToAll(ArrayList roomSetting, String name, String msg) {

Iterator it = chatRoom.get(roomSetting).keySet().iterator();

while (it.hasNext()) {

try {

DataOutputStream out = (DataOutputStream) chatRoom.get(roomSetting).get(it.next());

out.writeUTF("[" + name + "] : " + msg);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}


void makeRoom(ArrayList roomSetting, ArrayList clientSetting, DataOutputStream out) { // 방제, 클라이언트 이름, 쏴줄 곳

clients = new HashMap<>();

clients.put(clientSetting, out);

chatRoom.put(roomSetting, clients);

}


void showRoomList(DataOutputStream out) {

try {

if (chatRoom.isEmpty())

out.writeUTF("개설된 대화방이 없습니다.");

else {

Iterator it = chatRoom.entrySet().iterator(); // arraylist(방제, 비번), hashmap <리스트, 대화방> 나옴

while (it.hasNext()) {

Map.Entry e = (Map.Entry) it.next();

if (((ArrayList) e.getKey()).size() >= 2) { // 비번 걸린 방

out.writeUTF((String) ((ArrayList) e.getKey()).get(0) + " (비밀방) : "

+ ((HashMap) e.getValue()).size() + "명 접속중");

} else { // 비번 안 걸린 방

out.writeUTF((String) ((ArrayList) e.getKey()).get(0) + " : " + ((HashMap) e.getValue()).size()

+ "명 접속중");

}

}

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}


void showClientList(DataOutputStream out, String roomName) {

Iterator it = chatRoom.keySet().iterator();

ArrayList al = null;

while (it.hasNext()) {

ArrayList al2 = (ArrayList)it.next();

if(al2.get(0).equals(roomName)) {

al = al2;

}

}

it = chatRoom.get(al).keySet().iterator();

while (it.hasNext()) {

try {

out.writeUTF("이름 : " + (String)((ArrayList)it.next()).get(0));

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

} // 완료


void selectRoom(ArrayList roomSetting, ArrayList clientSetting, DataOutputStream out) { // 방제, 비번, 클라이언트 이름, 방장 여부,

// 쏴줄 곳

chatRoom.get(roomSetting).put(clientSetting, out); // 방제에 해당하는 대화방(hashmap)에 클라이언트 이름,방장여부 / 클라이언트에게 쏴줄 아웃풋 넣음

try {

out.writeUTF("현재 접속자 수는 " + chatRoom.get(roomSetting).size() + "명 입니다");

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}


void roomBoom(String roomName, DataOutputStream out) { // 방 폭파

Iterator it = chatRoom.keySet().iterator();

while(it.hasNext()) {

ArrayList al = (ArrayList)it.next();

if(al.get(0).equals(roomName)) {

try {

out.writeUTF("방이 폭파되었습니다");

chatRoom.remove(al);

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

} //완료


void kickClient(DataOutputStream out, DataInputStream in, String roomName) { // 특정 클라이언트 퇴출

try {

out.writeUTF("----------------강퇴리스트----------------");

showClientList(out, roomName); // 강퇴 리스트를 보여줌

out.writeUTF("강퇴하고 싶은 사람의 이름을 입력해주세요");

String name = in.readUTF();

Iterator it = clients.keySet().iterator(); // 이름은 clients의 key에 있다

int count = 0;

while(it.hasNext()) {

count++;

ArrayList al = (ArrayList)it.next();

if(al.get(0).equals(name)) { // 이름과 일치하면

clients.remove(al); // 삭제

out.writeUTF(name + "님을 강퇴했습니다");

}

if(!al.get(0).equals(name) && count == clients.size()) {

out.writeUTF("해당 유저가 없습니다");

}

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}


void changePassword(String roomName, DataOutputStream out, DataInputStream in) { // 비번 변경

Iterator it = chatRoom.keySet().iterator();

while(it.hasNext()) {

ArrayList al = (ArrayList)it.next();

if(al.get(0).equals(roomName)) {

try {

out.writeUTF("새비밀번호를 입력하세요");

al.add(in.readUTF());

out.writeUTF("비밀번호가 변경되었습니다");

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

}

} // 이상함


void grantRight(String roomName, DataOutputStream out, DataInputStream in) { // 방장 권한 주기

try {

out.writeUTF("----------------권한 부여 리스트----------------");

showClientList(out, roomName); // 강퇴 리스트를 보여줌

out.writeUTF("방장 권한을 주고 싶은 사람의 이름을 입력해주세요");

String name = in.readUTF();

Iterator it = clients.keySet().iterator(); // 이름은 clients의 key에 있다

int count = 0;

while(it.hasNext()) {

count++;

ArrayList al = (ArrayList)it.next();

if(al.get(0).equals(name)) { // 이름과 일치하면

al.remove(1);

al.add(true);

out.writeUTF(name + "님에게 권한을 부여했습니다");

}

if(!al.get(0).equals(name) && count == clients.size()) {

out.writeUTF("해당 유저가 없습니다");

}

}

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

} // 이상함


public static void main(String[] args) {

new ChatServer().start();

}


class ServerReceiver extends Thread {

Socket chSocket; // 채팅 소켓

Socket fiSocket; // 파일 소켓

DataInputStream in;

DataOutputStream out;


ServerReceiver(Socket chSocket, Socket fiSocket) {

this.chSocket = chSocket;

this.fiSocket = fiSocket;

try {

in = new DataInputStream(chSocket.getInputStream());

out = new DataOutputStream(chSocket.getOutputStream());

} catch (IOException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}


public void run() {

ArrayList<String> roomSetting = null; // get(0)은 방이름(String), get(1)은 방 비번(String)

ArrayList clientSetting = null; // get(0)은 이름(String), get(1)은 방장 여부(boolean)

String roomName = ""; // chatRoom의 특정key의 get(0) (방 제목)

String password = ""; // chatRoom의 특정key의 get(1) (방 비번)

String name = ""; // chatRoom의 특정 value의 key의 get(0) (클라이언트 이름)

boolean isMaster = false; // chatRoom의 특정 value의 key의 get(1) (클라이언트의 방장 여부)


try {

showRoomList(out);

out.writeUTF("[1] 대화방 들어가기 or [2] 대화방 새로 만들기");

int select = Integer.parseInt(in.readUTF());

if (chatRoom.isEmpty() && select == 1) {

out.writeUTF("개설된 대화방이 없으니 대화방을 새로 만들어주세요");

select = 2;

}

while (select != 1 && select != 2) {

out.writeUTF("잘못 입력하셨습니다");

out.writeUTF("[1] 대화방 들어가기 or [2] 대화방 새로 만들기");

select = Integer.parseInt(in.readUTF());

if (select == 1 && chatRoom.isEmpty()) {

out.writeUTF("개설된 대화방이 없으니 대화방을 새로 만들어주세요");

select = 2;

}

}


if (select == 1) {

out.writeUTF("본인의 이름을 입력해주세요");

name = in.readUTF();

clientSetting = new ArrayList();

clientSetting.add(name);

clientSetting.add(isMaster);


outer: while (true) {

out.writeUTF("대화방을 선택해 주세요");

roomName = in.readUTF();

// roomName과 일치하는 roomName을 가지고 있는 array객체를 찾아야 한다 >> array객체는 chatRoom의 키에 있다.

Iterator it = chatRoom.keySet().iterator();

while (it.hasNext()) {

roomSetting = ((ArrayList) it.next());

if (roomSetting.get(0).equals(roomName)) { // roomName이 chatRoom의 Array객체를 순회하며 일치하는

if (roomSetting.size() >= 2) { // 비밀 번호가 걸려있는 방이면

out.writeUTF("비밀번호를 입력해주세요"); // 비번을 입력받는다

if (roomSetting.get(roomSetting.size()-1).equals(in.readUTF())) { // 비번 일치한다면

selectRoom(roomSetting, clientSetting, out);

sendToAll(roomSetting, name, "님이 들어오셨습니다.");

break outer; // 찾으면 전체 while문 빠져나감

} else { // 비번이 일치하지 않으면

out.writeUTF("비밀번호가 일치하지 않습니다");

it = chatRoom.keySet().iterator();

continue; // 안쪽 while문 돌게해서 다시 입력받게함

}

} else { // 비밀 번호가 안 걸려있으면

selectRoom(roomSetting, clientSetting, out);

sendToAll(roomSetting, name, "님이 들어오셨습니다.");

break outer; // 찾으면 전체 while문 빠져나감

}

}

}

// 해당하는 방제목을 찾지 못함 > 다시 돌려야함.

out.writeUTF("해당하는 방 이름을 찾지 못했습니다, 다시 입력해주세요");

}


} else if (select == 2) {

isMaster = true; // 개설한 사람이 방장

out.writeUTF("방을 개설합니다");

out.writeUTF("본인의 이름을 입력해주세요");

name = in.readUTF();

clientSetting = new ArrayList();

clientSetting.add(name);

clientSetting.add(isMaster);

if (chatRoom.isEmpty()) {

out.writeUTF("방 제목을 정해주세요");

roomName = in.readUTF();

} else {

outer: while (true) {

out.writeUTF("방 제목을 정해주세요");

roomName = in.readUTF();

Iterator it = chatRoom.keySet().iterator();

ArrayList al = null;

int count = 0;

while (it.hasNext()) {

count++;

al = (ArrayList) it.next();

if (al.get(0).equals(roomName)) { // roomName이 chatRoom의 Array객체를 순회하며 일치하는 방제를 찾으면

out.writeUTF("이미 존재하는 방 이름입니다, 방제를 다시 설정해주세요");

showRoomList(out);

break; // 나가서 올바른 방제를 입력할 때까지 돌리게함

} else if (!(al.get(0).equals(roomName)) && count == chatRoom.size()) { //

break outer;

}

}

}

}

out.writeUTF("비밀번호를 설정하시겠습니까? Y/N");

String answer = in.readUTF().toLowerCase();

while (!answer.equals("y") && !answer.equals("n")) {

out.writeUTF("잘못 입력하셨습니다");

out.writeUTF("비밀번호를 설정하시겠습니까? Y/N");

answer = in.readUTF().toLowerCase();

}


if (answer.equals("y")) {

out.writeUTF("비밀번호를 설정해주세요");

password = in.readUTF();

roomSetting = new ArrayList<>();

roomSetting.add(roomName);

roomSetting.add(password);

makeRoom(roomSetting, clientSetting, out);

out.writeUTF("대화방이 개설되었습니다");

} else if (answer.equals("n")) {

roomSetting = new ArrayList<>();

roomSetting.add(roomName);

makeRoom(roomSetting, clientSetting, out);

out.writeUTF("대화방이 개설되었습니다");

}


}

while (in != null) {

String readLine = in.readUTF();

if (readLine.equals("/방폭하기") && (boolean) clientSetting.get(1)) {

roomBoom(roomName, out);

} else if (readLine.equals("/방폭하기") && !(boolean) clientSetting.get(1)) {

out.writeUTF("권한이 없습니다");

} else if (readLine.equals("/강퇴하기") && (boolean) clientSetting.get(1)) {

kickClient(out ,in, roomName);

} else if (readLine.equals("/강퇴하기") && !(boolean) clientSetting.get(1)) {

out.writeUTF("권한이 없습니다");

} else if (readLine.equals("/비번 변경하기") && (boolean) clientSetting.get(1)) {

changePassword(roomName, out, in);

} else if (readLine.equals("/비번 변경하기") && !(boolean) clientSetting.get(1)) {

out.writeUTF("권한이 없습니다");

} else if (readLine.equals("/방장 권한주기") && (boolean) clientSetting.get(1)) {

grantRight(roomName, out, in);

} else if (readLine.equals("/방장 권한주기") && !(boolean) clientSetting.get(1)) {

out.writeUTF("권한이 없습니다");

} else if (readLine.equals("/파일 보내기")) {

out.writeUTF("보낼 파일을 입력하세요");

sendFileToAll(roomSetting, in.readUTF(), name, out);

} else if (readLine.equals("/사람 목록")) {

showClientList(out, roomName);

}

else

sendToAll(roomSetting, name, readLine);

}

} catch (IOException e) {


} finally {

chatRoom.get(roomSetting).remove(clientSetting);

sendToAll(roomSetting, "관리자", "[" + chSocket.getInetAddress() + ":" + chSocket.getPort() + "]" + "["

+ name + "] 님께서 접속을 종료하였습니다.");

sendToAll(roomSetting, "관리자", "현재 접속자 수는 " + chatRoom.get(roomSetting).size() + "명 입니다");

}

}

}

}


대화방 만들고 그 안에서만 채팅 다 되고 방 리스트 보여주고 비밀방 시스템도 되고 방 안에있는 사람 목록 보기도 되는데


방장 권한을