(자바)소켓 통신 - 양방향 채팅
2021. 6. 23. 00:33ㆍ(구)공부/JAVA
728x90
중앙 서버를 두고 여러 클라이언트가 접속하여 채팅하는 프로그램
동작 흐름
서버 기동 -> 클라이언트의 접속 요청 대기 -> 클라이언트에서 접속 요청-> 통신 소켓 생성
클라이언트 코드
public class Client extends Common {
public static void main(String[] args) {
System.out.println("스프링 채팅방 클라이언트를 시작합니다...");
Client aClient = new Client();
aClient.execute();
}
Socket cSock;
DataInputStream inStream;
DataOutputStream outStream;
private void execute() {
try {
cSock = new Socket(SERVER_IP, SERVER_PORT);
} catch (UnknownHostException e) {
System.out.printf("서버를 찾을 수 없음 : [%s]\n", SERVER_IP);
return;
} catch (IOException e) {
System.out.println("서버가 실행되고 있지 않습니다...");
return;
}
try {
inStream = new DataInputStream(cSock.getInputStream());
outStream = new DataOutputStream(cSock.getOutputStream());
// 채팅 시작 : 2개의 모드로 분리
// Write Mode는 바로 구현
Scanner aScanner = new Scanner(System.in);
String aMessage;
while(true) {
System.out.print("채팅에 사용할 닉네임 : ");
aMessage = aScanner.nextLine();
if(aMessage.isEmpty()) {
System.out.println("올바른 닉네임이 아닙니다...");
continue;
}
outStream.writeUTF(aMessage); // 닉네임을 서버로 전송
break;
}
// Read Mode 쓰레드 생성 : 내부의 run()이 쓰레드로 호출됨
new Thread(this).start();
while(true) {
System.out.print("대화 > ");
aMessage = aScanner.nextLine();
outStream.writeUTF(aMessage);
}
} catch (IOException e) {
System.out.println("채팅 서버 문제로 종료합니다...");
System.exit(0);
}
}
@Override
public void run() { // 채팅 : Read Mode
String aMessage;
while(true) {
try {
aMessage = inStream.readUTF();
System.out.println("\n\n"+aMessage+"\n");
System.out.print("대화 > ");
} catch (IOException e) {
System.out.println("채팅 서버 문제로 종료합니다...");
System.exit(0);
}
}
}
}
공통 코드
import java.text.SimpleDateFormat;
import java.util.Date;
public class Common implements Runnable {
public static final String STOPMESSAGE = "EXIT";
public static final String SIP = "자신의 IP";
public static final int SPORT = 7777; // 자신이 사용할 포트를 지정. 낮은 번호대는
//사용처가 정해진 포트가 많으므로 조심한다.
@Override
public void run() {
}
public String getTime() {
SimpleDateFormat f = new SimpleDateFormat("[hh:mm:ss]");
return f.format(new Date());
}
}
서버코드
class Phone extends Common {
static Vector<Phone> aList = new Vector<Phone>();// 클라이언트 객체 목록
String cNickName;
Socket cSock;
DataInputStream inStream;
DataOutputStream outStream;
@Override
public void run() { // 클라이언트와의 채팅 구현
try {
outStream.writeUTF("[공지사항]:스프링 과정 채팅 서버에 입장하셨습니다...");
//대화 :chatting
String aMessage;
cNickName = inStream.readUTF();
aMessage = String.format("[공지사항]:%s님이 입장하셨습니다...",cNickName);
System.out.printf("\n%s\n",aMessage);
System.out.print("공지사항 입력 : ");
SendMessage(aMessage, this);
while(true) {
aMessage = inStream.readUTF();
aMessage = String.format("[%s]%s",cNickName, aMessage);
System.out.printf("\n%s\n",aMessage);
System.out.print("공지사항 입력 : ");
SendMessage(aMessage, this);
}
//outStream.writeUTF("[공지사항]:채팅방을 나가셨습니다...");
} catch (IOException e) {
aList.remove(this);
String aMessage = String.format("[알림]:[%s]님이 나가셨습니다...", cNickName);
System.out.printf("\n%s\n", aMessage); // 서버에 통보
SendMessage(aMessage, this); // 클라이언트들에게 통보
System.out.println("현재 접속자 수 : " + aList.size());
System.out.print("공지사항 입력 : ");
}
}
public static void SendMessage(String aMessage, Phone aPhone) {
for(Phone Temp : aList) {
if(aPhone == Temp) {
continue;
}
try {
Temp.outStream.writeUTF(aMessage);
} catch (IOException e) {
System.out.println("이거 뜨면 여기 다시 코딩");
}
}
}
public Phone(Socket cSock) { // 소켓에 해당하는 인풋, 아웃풋 스트림을 가져 옴
this.cSock = cSock;
try {
inStream = new DataInputStream(cSock.getInputStream());
outStream = new DataOutputStream(cSock.getOutputStream());
} catch (IOException e) {
e.printStackTrace();
}
aList.add(this);
System.out.println("\n현재 접속자 수 : " + aList.size());
}
}
public class Server extends Common {
public static void main(String[] args) {
System.out.println("Server Start...");
Server aServer = new Server();
aServer.execute();
}
@Override
public void run() {
Scanner aScanner = new Scanner(System.in);
String sMessage;
System.out.println("\n"+getTime()+"공지사항 기능이 활성화 되었습니다.");
while(true) {
System.out.print("공지사항 입력 : ");
sMessage = aScanner.nextLine();
if(sMessage.equals(STOP_MESSAGE)) {
Phone.SendMessage(sMessage, null);
break;
}
sMessage = String.format("[공지사항]:[%s]", sMessage);
System.out.printf("\n%s\n", sMessage);
Phone.SendMessage(sMessage, null);
}
System.out.println("종료를 위해 공지사항 기능을 비활성화 합니다.");
aScanner.close();
// 쓰레드를 강제 정지 시키고
// 스트림과 소켓을 모두 닫는다.
for(Phone Temp : Phone.aList) {
//Temp.interrupt();
try {
Temp.inStream.close();
Temp.outStream.close();
Temp.cSock.close();
} catch (IOException e) {
}
}
Phone.aList.removeAllElements();
try {
sSocket.close();
sSocket = null;
} catch (IOException e) {
System.out.println("소켓을 닫는 중에 IO 예외가 발생하였습니다...");
}
System.out.println("서버 쓰레드 종료합니다...");
}
private ServerSocket sSocket;
public Server() {
}
public void execute() {
createSocket();
new Thread(this).start(); // run을 쓰레드로 실행:Scanner 활성화
while(true) {
System.out.println(getTime()+"연결요청을 기다립니다.");
System.out.print("공지사항 입력 : ");
try {
Socket socket = sSocket.accept();
if (sSocket == null) {
System.out.println("채팅 서버 종료합니다...");
break;
}
System.out.println(
"\n"
+ getTime()
+ socket.getInetAddress().toString().substring(1)
+ "로부터 연결요청이 들어왔습니다."
);
//////////////////////////////////////
// 클라이언트 쓰레드 생성
new Thread(new Phone(socket)).start();
//////////////////////////////////////
} catch (IOException e) {
System.out.println("IO 문제 발생");
break;
}
}
}
private void createSocket() {
try {
sSocket = new ServerSocket(SERVER_PORT);
} catch (IllegalArgumentException e) {
System.out.println("잘못된 포트 번호 사용");
return;
} catch (IOException e) {
System.out.println("프로세서에서 포트가 선점되었습니다["+SERVER_PORT+"]");
System.out.println("서버가 실행 불가능하여 종료합니다...");
System.exit(0);
}
System.out.println(getTime()+"서버가 준비되었습니다...");
}
}
728x90
'(구)공부 > JAVA' 카테고리의 다른 글
JDBC (0) | 2021.07.08 |
---|---|
Swing - window builder (0) | 2021.07.07 |
JUnit (0) | 2021.07.07 |