
1. 일대일 채팅 프로그램
● CalcServer.java
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class CalcServer {
public static void main(String[] args) {
ServerSocket ss = null;
Socket socket = null;
try {
ss = new ServerSocket(9999);
System.out.println("서버가 구동중입니다.");
socket = ss.accept();
InputStream is = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(is);
CalcDTO dto = (CalcDTO)ois.readObject();
CalcDAO dao = new CalcDAO();
int result = dao.getResult(dto);
System.out.println("첫 번째 정수 : " + dto.getNum1());
System.out.println("두 번째 정수 : " + dto.getNum2());
System.out.println("연산자 : " + dto.getOpCode());
System.out.println("결과 : " + result);
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.println(result);
pw.flush();
pw.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
socket.close();
ss.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}//main()
}//class
① ServerSocket, Socket 생성 ▶ ServerSocket에 포트를 할당한다.
② 수신 스레드 객체 생성 후 start() 메서드, socket을 매개 변수로 넣는다.
③ 송신 스레드 객체 생성 후 start() 메서드, socket을 매개 변수로 넣는다.
④ 서버 소켓을 닫아준다, 소켓은 스레드에서 사용하기 때문에 서버에서 닫지 않는다.
● ChatClient.java
import java.net.Socket;
public class ChatClient {
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket("192.168.0.170", 9999);
//키보드에서 메세지를 입력받아 서버로 보내는 작업(송신, 출력) ▶ 보내는 Thread
Thread st = new ChatSenderThread(socket);
st.start();
} catch (Exception e) {
e.printStackTrace();
}
/*
finally {
try {
//socket.close();
// ▶ 여러번 전송해야하기 때문에 finally 구문에서
// socket을 close하면 한번 이상 전송이 안된다.
} catch (Exception e) {
e.printStackTrace();
}
}
*/
}//main()
}//class
① Socket 생성 ▶ 서버의 ip와 포트를 할당한다.
② 송신 스레드 객체 생성 후 start() 메서드 ▶ socket을 매개 변수로 넣는다.
③ 수신 스레드 객체 생성 후 start() 메서드 ▶ socket을 매개 변수로 넣는다.
④ 소켓은 스레드에서 사용하기 때문에 클라이언트에서 닫지 않는다.
● ChatSenderThread.java
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
//보내는 Thread : 메세지를 송신(출력) ▶ PrintWriter
public class ChatSenderThread extends Thread{ //Thread Class를 상속
private Socket socket;
public ChatSenderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("전송할 메세지를 입력하세요 : ");
String msg = scanner.nextLine();
if (msg.equals("bye")) {
System.out.println("종료되었습니다.");
System.exit(0); //메모리에서 완전히 제거하기 위해서
break;
}
pw.println(msg);
pw.flush(); //강제전송
}//while
scanner.close();
pw.close();
} catch (Exception e) {
e.printStackTrace();
System.out.println("ChatSenderThread Exception!");
} finally { //Client와 Server에서 닫지 않은 socket을 Thread에서 닫아야한다.
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}//try-catch
}//try-catch-finally
}//run()
}//class
① 소켓을 매개 변수로 받기 때문에 멤버 변수로 선언하고 기본 생성자 메서드를 만든다.
② Thread 클래스를 상속받고 run() 메서드를 오버라이드 한다.
③ 문자를 송신하기 때문에 OutputStream, PrintWriter 브릿지를 만든다.
④ 키보드로 입력하기 위해 Scanner 클래스 객체를 만든다.
⑤ 메시지를 계속 입력하기 위해 while() 문을 사용한다.
⑥ 메시지를 입력하는 문단을 while() 문 내부에 작성하고 종료 단어 bye를 만든다.
⑦ 메시지를 송신하기 위해 pw.prinln()과 pw.flush() 메서드를 사용한다.
⑧ 사용이 끝난 스캐너와 소켓을 닫아준다.
● ChatReceiverThread.java
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
//받는 Thread : 메세지를 소신(입력) ▶ BufferedReader
public class ChatReceiverThread extends Thread{
private Socket socket;
public ChatReceiverThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
while (true) {
String msg = br.readLine();
if (msg == null) {
System.exit(0); //메모리 정리
break;
}
System.out.println("수신 메세지 : " + msg);
}//while
br.close();
} catch (Exception e) {
//e.printStackTrace();
//System.out.println("ChatReceiverThread Exception!");
System.out.println("종료되었습니다.");
} finally {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}//run()
}//class
① 소켓을 매개 변수로 받기 때문에 멤버 변수로 선언하고 기본 생성자 메서드를 만든다.
② Thread 클래스를 상속받고 run() 메서드를 오버라이드 한다.
③ 문자를 수신하기 때문에 InputStream, InputStreamReader, BufferedReader 브릿지를 만든다.
④ 누가 접속했는지 알기 위해 getInetAddress()와 getHostName()으로 접속자 이름을 받는다.
⑤ 메시지를 계속 수신하기 위해 while() 문을 사용한다.
⑥ while() 문 내부에 수신받는 문단을 작성하고 종료 단어 bye가 입력되었을 때 종료되는 문단도 작성한다.
⑦ 사용이 끝난 소켓을 닫아준다.

2. 단체 채팅 프로그램
● MultiChatServer.java
import java.net.ServerSocket;
import java.net.Socket;
public class MultiChatServer {
public static void main(String[] args) {
ServerSocket ss = null;
Socket socket = null;
try {
ss = new ServerSocket(9999);
System.out.println("서버가 구동중입니다.");
while (true) { //서버에는 다수의 클라이언트가 접속 → 접속된 클라이언트만큼 Socket을 생성
socket = ss.accept();
Thread pt = new MultiChatPersonThread(socket); //다수의 클라이언트에서 동작되는 스레드
pt.start();
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("MultiChatServer Exception!");
}
/*
finally {
try {
//socket.close();
//ss.close();
} catch (Exception e) {
e.printStackTrace();
}
}
*/
}//main()
}//class
① ServerSocket, Socket 생성 ▶ ServerSocket에 포트를 할당한다.
② 불특정 다수가 서버로 들어오기 때문에 while() 문을 사용한다.
③ while() 문 내부에 여러 접속을 받기 위한 Person 스레드 객체 생성 후 start() 메서드, socket을 매개 변수로 넣는다.
④ 서버 소켓과 소켓을 스레드에서 사용하기 때문에 서버에서 닫지 않는다.
● MultiChatClient.java
import java.net.Socket;
public class MultiChatClient {
public static void main(String[] args) {
Socket socket = null;
try {
socket = new Socket("192.168.35.241", 9999);
//클라이언트 프로그램 실행 시 대화명이 미입력 되었을 때
//사용법을 안내하는 메세지 출력
if (args.length != 1) {
System.out.println("프로그램 실행 시 대화명을 입력해주세요!");
System.out.println("실행 예 : java MultiChatClient 대화명");
}
//메세지를 입력받아 서버로 보내는 작업(송신, 출력) ▶ MultiChatSenderThread
Thread st = new MultiChatSenderThread(socket, args[0]);
st.start();
//메세지를 수신(입력)받아 화면에 출력하는 작업 ▶ MultiChatReceiverThread
Thread rt = new MultiChatReceiverThread(socket);
rt.start();
} catch (Exception e) {
e.printStackTrace();
System.out.println("MultiChatClient Exception!");
} /*finally {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}*/
}//main()
}//class
① Socket 생성 ▶ 서버의 ip와 포트를 할당한다.
② 대화명을 args [] 배열에 받도록 안내문을 작성한다.
③ 송신 스레드 객체 생성 후 start() 메서드 ▶ socket을 매개 변수로 넣는다.
④ 수신 스레드 객체 생성 후 start() 메서드 ▶ socket을 매개 변수로 넣는다.
⑤ 소켓은 스레드에서 사용하기 때문에 클라이언트에서 닫지 않는다.
● MultiChatSenderThread.java
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class MultiChatSenderThread extends Thread{ //송신, 출력 →PrintWriter
private Socket socket;
private String name;
public MultiChatSenderThread(Socket socket, String name) {
this.socket = socket;
this.name = name;
}
@Override
public void run() {
try {
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.println(name);
pw.flush();
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("서버로 전송할 메세지를 입력하세요 : ");
String msg = scanner.nextLine();
if (msg.equals("bye")) {
scanner.close();
pw.close();
break;
}//if
pw.println(msg);
pw.flush();
}//while
} catch (Exception e) {
e.printStackTrace();
System.out.println("MultiChatSenderThread Exception!");
} finally {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}//try-catch-finally
}//run()
}//class
① 소켓과 대화명을 매개 변수로 받기 때문에 멤버 변수로 선언하고 기본 생성자 메서드를 만든다.
② Thread 클래스를 상속받고 run() 메서드를 오버라이드 한다.
③ 문자를 송신하기 때문에 OutputStream, PrintWriter 브릿지를 만든다.
④ 매개 변수로 받은 대화명을 송신하기 위해 pw.prinln()과 pw.flush() 메서드를 사용한다.
⑤ 키보드로 입력하기 위해 Scanner 클래스 객체를 만든다.
⑥ 메시지를 계속 입력하기 위해 while() 문을 사용한다.
⑦ 메시지를 입력하는 문단을 while() 문 내부에 작성하고 종료 단어 bye를 만든다.
⑧종료할 때 사용이 끝난 PrintWriter 브릿지와 Scanner 클래스를 닫아 준다.
⑨ 입력받은 메시지를 송신하기 위해 pw.prinln()과 pw.flush() 메서드를 사용한다.
⑩ 사용이 끝난 소켓을 닫아준다.
● MultiChatReceiverThread.java
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class MultiChatReceiverThread extends Thread{ //수신, 입력 → BufferedReader
private Socket socket;
public MultiChatReceiverThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
while (true) {
String msg = br.readLine();
if (msg == null) {
br.close();
break;
}
System.out.println(msg);
}//while
} catch (Exception e) {
e.printStackTrace();
System.out.println("MultiChatReceiverThread Exception!");
} finally {
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}//run()
}//class
① 소켓을 매개 변수로 받기 때문에 멤버 변수로 선언하고 기본 생성자 메서드를 만든다.
② Thread 클래스를 상속받고 run() 메서드를 오버라이드 한다.
③ 문자를 수신하기 때문에 InputStream, InputStreamReader, BufferedReader 브릿지를 만든다.
④ 메시지를 계속 수신하기 위해 while() 문을 사용한다.
⑤ while() 문 내부에 수신받는 문단을 작성하고 종료 단어 bye가 입력되었을 때 종료되는 문단도 작성한다.
⑥ 종료할 때 사용이 끝난 BufferedReader 브릿지도 닫아준다.
⑦ 사용이 끝난 소켓을 닫아준다.
● MultiChatPersonThread.java
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
//접속된 다수의 클라이언트에서 동작되는 스레드
//접속된 모든 클라이언트의 접속 정보를 저장하고
//접속된 클라이언트에게 메세지를 전송(송신, 수신)할 수 있도록
//클라이언트의 목록을 저장할 무한 배열을 만들자 → ArrayList<>
//MultiChatServer Class의 main() 메소드와 같이 동작 : static
public class MultiChatPersonThread extends Thread{
private Socket socket;
private PrintWriter pw;
static ArrayList<PrintWriter> list = new ArrayList<>();
public MultiChatPersonThread(Socket socket) {
this.socket = socket;
try {
OutputStream os = socket.getOutputStream();
pw = new PrintWriter(os);
list.add(pw);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
String name = null;
InetAddress addr = socket.getInetAddress();
String comName = addr.getHostName();
try {
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
//클라이언트에서 맨 처음에 입력된 메세지(대화명)을 받아
//접속된 다른 클라이언트 화면에 출력 ▶ sendAll()
name = br.readLine();
sendAll("#" + name + "(" + comName + ")님께서 입장하셨습니다!");
// #홍길동(201-xx)님께서 입장하셨습니다!
//클라이언트에서 보낸 메세지(대화 내용)를 접속된 다른 클라이언트에게 전송
while (true) {
String msg = br.readLine();
if (msg == null) {
break;
}//if
sendAll(name + "(" + comName + ") : " + msg);
// #홍길동(201-xx) : 안녕하세요
}//while
} catch (Exception e) {
e.printStackTrace();
System.out.println("MultiChatPersonThread Exception");
} finally {
try {
list.remove(pw); //접속 목록에서 삭제
sendAll("#" + name + "(" + comName + ")님께서 퇴장하셨습니다!");
// #홍길동(201-xx)님께서 퇴장하셨습니다!
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}//try-catch-finally
}//run()
public void sendAll(String msg) {
for (PrintWriter pw : list) {
pw.println(pw);
pw.flush();
}//for-each
}//sendAll()
}//class
① 제일 먼저 접속한 클라이언트의 모든 정보를 받도록 static을 사용하여 초기화 블록을 만들어준다.
② 초기화 블록에 PrintWriter 타입만 다루도록 제네릭스를 설정한 ArrayList를 선언 및 초기화해준다.
③ 멤버 변수 Socket과 PrintWriter를 선언하고 socket을 매개변수로 받는 생성자를 만들어준다.
④ (추후 수정)
⑤ Thread 클래스를 상속받고 run() 메서드를 오버 라이딩한다.
⑥ 접속한 사람의 정보를 알기 위해 getInetAddress()와 getHostName() 메서드를 사용한다.
⑦ 대화명 name을 readLine()으로 입력받고 sendAll로 입장 메시지를 접속해 있는 사용자들에게 뿌려준다.
⑧ 사용자가 입력한 내용을 String msg로 받아서 뿌려준다.
⑨ 퇴장 시 퇴장 메시지를 뿌려준다.
