네트워크
스레드
ChatServer은 ServerSocket을 가지고 있는다.
ServerSocket은 클라이언트가 들어올 때까지 accept로 기다린다.
ChatClient가 소켓을 가지고 들어온다.
ServerSocket은 accept로 해서 socket이 만들어진다.
만들어진 socket을 ChatHandler한테 던져준다.
ChatHandler는 socket을 가지고 클라이언트를 기다린다.
실제 대화는 ChatClient - ChatHandler 전용 소켓 1대1인 것이다.
또 다른 클라이언트가 들어오면 ChatServer가 낚아채서 소켓을 만들고 또 다른 ChatHandler가 만들어진다.
ChatHandler가 스레드가 되는 것이다.
각자 전용 소켓들이 연결되는 것이다.
안녕해서 클라이언트가 보내주면 그게 핸들러한테 가고 다시 클라이언트한테 돌아온다.
핸들러는 나한테 뭐가 오면 다 뿌려주고 이런 역할을 한다.
소켓은 1대1이므로 다른 클라이언트한테 갈 수 없다.
소켓을 담아놔야한다. 몇명의 채팅수가 들어왔는지 알 수 있는 것 - ChatServer가 갖고있다.
채팅자수를 ChatServer가 보관하자. ArrayList에 담을 수 있고, Map에 담을 수도 있다.
Map<String, ChatHandler> - chatRoom
"apple@192.168.0.42" | ChatHandler( 소켓, IO)
key value
"banana@192.168.0.50" | ChatHandler( 소켓, IO_)
key value
Client가 들어오며 Handler가 같이 만들어짐 그래야 대화할 수 있으므로
Socket socket = serverSocket.accept(); //연결수락하고, 통신용 ChatHandler를 반복해서 생성
ChatHandler chatHandler = new ChatHandler(this, socket);
JSON 데이터 형식
=> *.jar 필요
json-20231013.jar
=> 네트워크로 전달하는 데이터가 복잡할수록 구조화된 형식이 필요하다.
네트워크 통신에서 가장 많이 사용되는 데이터 형식은 JSON(JavaScript Object Notation)이다.
[형식]
① JSON 객체
{
"속성명" : 값,
"속성명" : 값
}
② JSON 배열
[
"문자열" or
{ ......} or
[ ......]
]
ChatServer.java
package network;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.json.JSONObject;
public class ChatServer {
//서버소켓 - 클라이언트의 연결 요청을 수락
ServerSocket serverSocket;
//100개의 클라이언트가 동시에 채팅할 수 있는 스레드 풀
ExecutorService threadPool = Executors.newFixedThreadPool(100);
//통신용 ChatHandler를 관리하는 동기화된 Map 컬렉션
Map<String, ChatHandler> chatRoom = Collections.synchronizedMap(new HashMap<>());
1. ServerSocket serverSocket
ServerSocket 객체는 서버가 클라이언트의 연결 요청을 수락할 수 있도록 한다.
- 서버 소켓 생성: 서버는 특정 포트에서 클라이언트의 연결을 기다린다.
- 연결 수락: 클라이언트가 서버에 연결을 요청하면, ServerSocket은 그 요청을 수락하고 새로운 Socket 객체를 생성하여 클라이언트와의 통신을 담당한다.
2. ExecutorService threadPool
ExecutorService는 스레드 풀을 관리하는 인터페이스로, 서버가 동시에 여러 클라이언트의 요청을 처리할 수 있도록 한다. 여기서는 고정된 100개의 스레드가 포함된 스레드 풀을 사용한다.
- 스레드 풀 생성: Executors.newFixedThreadPool(100)을 사용하여 100개의 스레드를 포함한 스레드 풀을 생성한다.
- 작업 제출: 클라이언트의 요청이 있을 때마다, 해당 요청을 처리하기 위해 스레드 풀에 작업을 제출한다. 이는 서버가 높은 동시성을 처리할 수 있게 한다.
3. Map<String, ChatHandler> chatRoom
Map 컬렉션은 서버가 각 클라이언트와의 통신을 관리하는 ChatHandler 객체를 저장하는 데 사용된다. Collections.synchronizedMap을 사용하여 동기화된 Map을 생성함으로써, 여러 스레드가 동시에 이 Map에 접근하는 경우에도 안전하게 접근할 수 있다.
- ChatHandler 관리: 클라이언트가 서버에 연결하면, 서버는 새로운 ChatHandler 객체를 생성하고 이를 Map에 저장하여 클라이언트와의 통신을 관리한다.
- 동기화: 동기화된 Map을 사용하여 다수의 스레드가 안전하게 Map에 접근하고 수정할 수 있도록 한다.
- 이 메서드는 서버가 9500번 포트에서 클라이언트의 연결 요청을 받아들이고, 각 클라이언트와의 통신을 처리하는 ChatHandler 객체를 생성하여 관리하도록 한다. 이를 통해 다수의 클라이언트가 동시에 서버와 통신할 수 있다.
//서버 시작하고 클라이언트의 연결 요청을 받아들인다.
private void start() throws IOException { //서버시작하는 거 알려주는 스타트
serverSocket = new ServerSocket(9500); //9500번 포트로 서버 소켓 생성.
System.out.println("서버 준비 완료");
//ChatServer가 스레드면 Thread thread = new Thread(this);
Thread thread = new Thread(() -> { //새 스레드 생성, Runnable를 람다식 제공
try {
while(true) {
Socket socket = serverSocket.accept(); //연결수락하고, 통신용 ChatHandler를 반복해서 생성
ChatHandler chatHandler = new ChatHandler(this, socket);//여기서 this로 서버의 주소를 보내서 ChatHandler가 받아야
// ChatServer에 있는 메소드를 불러 올 수 있다.
}//while
}catch(IOException e) {
//e.printStackTrace();
}
});
thread.start(); //스레드 시작
}//start()
ChatServer 클래스의 start 메서드는 서버를 시작하고 클라이언트의 연결 요청을 받아들이는 기능을 한다.
이 메서드는 주로 ServerSocket 객체를 생성하고, 클라이언트의 연결을 처리하는 스레드를 시작한다.
start 메서드의 구성
- 서버 소켓 생성
- 서버 준비 메시지 출력
- 새 스레드 생성 및 시작
1. 서버 소켓 생성
serverSocket = new ServerSocket(9500); // 9500번 포트로 서버 소켓 생성.
- ServerSocket 객체를 9500번 포트에서 생성한다.
- 이 객체는 서버가 클라이언트의 연결 요청을 수락할 준비를 한다.
2. 서버 준비 메시지 출력
System.out.println("서버 준비 완료");
- 서버가 정상적으로 시작되었음을 알리는 메시지를 콘솔에 출력한다.
- 이는 서버가 클라이언트의 연결 요청을 받아들일 준비가 되었음을 사용자에게 알린다.
3. 새 스레드 생성 및 시작
Thread thread = new Thread(() -> { // 새 스레드 생성, Runnable를 람다식 제공
try {
while (true) {
Socket socket = serverSocket.accept(); // 연결 수락하고, 통신용 ChatHandler를 반복해서 생성
ChatHandler chatHandler = new ChatHandler(this, socket); // 여기서 this로 서버의 주소를 보내서 ChatHandler가 받아야
// ChatServer에 있는 메소드를 불러 올 수 있다.
}
} catch (IOException e) {
// e.printStackTrace();
}
});
- 새 스레드 생성: 새로운 스레드를 생성한다. 이 스레드는 클라이언트의 연결 요청을 처리하는 역할을 한다.
- Runnable 인터페이스를 람다식으로 제공하여 스레드가 실행할 코드를 정의한다.
- 무한 루프 (while (true)): 서버가 계속해서 클라이언트의 연결 요청을 처리할 수 있도록 무한 루프를 사용한다.
- 연결 수락 (socket = serverSocket.accept()):
- serverSocket이 클라이언트의 연결 요청을 수락하면 새로운 Socket 객체를 생성한다.
- 이 Socket 객체는 클라이언트와의 통신을 담당한다.
- ChatHandler 생성 (new ChatHandler(this, socket)):
- 새로운 ChatHandler 객체를 생성한다.
- this 키워드를 사용하여 ChatServer 객체의 참조를 전달한다. 이를 통해 ChatHandler가 ChatServer의 메서드와 필드에 접근할 수 있다.
- socket 객체를 전달하여 클라이언트와의 통신을 관리한다.
4. 스레드 시작
thread.start(); // 스레드 시작
- 생성된 스레드를 시작한다. 이 스레드는 run 메서드 (여기서는 람다식으로 제공된 코드)를 실행하여 클라이언트의 연결 요청을 처리한다.
- 이 메서드는 새로운 클라이언트가 서버에 연결될 때 호출되어, 클라이언트를 chatRoom에 추가하고, 클라이언트의 입장과 현재 채팅방에 있는 클라이언트 수를 콘솔에 출력한다.
- 이를 통해 서버는 각 클라이언트를 효율적으로 관리하고 추적할 수 있다.
//클라이언트 연결 시 ChatHandler 생성 및 추가
//새로운 클라이언트 추가
public void addSocketClient(ChatHandler chatHandler) {
String key = chatHandler.chatName + "@" + chatHandler.clientIp;
chatRoom.put(key, chatHandler);
System.out.println("입장 : " + key);
System.out.println("현재 채팅자 수 : " + chatRoom.size() + "\n");
}
addSocketClient 메서드의 역할
- 클라이언트의 고유 키 생성
- 클라이언트의 ChatHandler 객체를 chatRoom에 추가
- 클라이언트 입장 메시지 출력
- 현재 채팅자 수 출력
1. 클라이언트의 고유 키 생성
String key = chatHandler.chatName + "@" + chatHandler.clientIp;
- chatHandler 객체의 chatName과 clientIp를 조합하여 고유한 키를 생성한다.
- chatName은 클라이언트의 이름을 나타내고, clientIp는 클라이언트의 IP 주소를 나타낸다.
- 이 키는 chatRoom 맵에서 클라이언트를 고유하게 식별하는 데 사용된다.
2. 클라이언트의 ChatHandler 객체를 chatRoom에 추가
chatRoom.put(key, chatHandler);
- 생성된 고유 키를 사용하여 chatRoom 맵에 chatHandler 객체를 추가한다.
- chatRoom은 Map<String, ChatHandler> 타입으로, 클라이언트의 고유 키와 해당 클라이언트의 ChatHandler 객체를 저장한다.
3. 클라이언트 입장 메시지 출력
System.out.println("입장 : " + key);
- 클라이언트가 채팅방에 입장했음을 알리는 메시지를 콘솔에 출력한다.
- 입장 메시지에는 클라이언트의 고유 키가 포함된다.
4. 현재 채팅자 수 출력
System.out.println("현재 채팅자 수 : " + chatRoom.size() + "\n");
- 현재 채팅방에 있는 클라이언트 수를 콘솔에 출력한다.
- chatRoom.size()를 사용하여 현재 맵에 저장된 ChatHandler 객체의 수를 가져온다.
- 이 메서드는 클라이언트가 서버와의 연결을 종료할 때 호출되어, 클라이언트를 chatRoom에서 제거하고, 클라이언트의 퇴장과 현재 채팅방에 있는 클라이언트 수를 콘솔에 출력한다. 이를 통해 서버는 각 클라이언트를 효율적으로 관리하고 추적할 수 있다.
//클라이언트 연결 종료 시 ChatHandler 제거 // 클라이언트 제거
public void removeSocketClient(ChatHandler chatHandler) {
String key = chatHandler.chatName + "@" + chatHandler.clientIp;
chatRoom.remove(key);
System.out.println("퇴장 : " + key);
System.out.println("현재 채팅자 수 : " + chatRoom.size() + "\n");
}
removeSocketClient 메서드의 역할
- 클라이언트의 고유 키 생성
- 클라이언트의 ChatHandler 객체를 chatRoom에서 제거
- 클라이언트 퇴장 메시지 출력
- 현재 채팅자 수 출력
1. 클라이언트의 고유 키 생성
String key = chatHandler.chatName + "@" + chatHandler.clientIp;
- chatHandler 객체의 chatName과 clientIp를 조합하여 고유한 키를 생성한다.
- chatName은 클라이언트의 이름을 나타내고, clientIp는 클라이언트의 IP 주소를 나타낸다.
- 이 키는 chatRoom 맵에서 클라이언트를 고유하게 식별하는 데 사용된다.
2. 클라이언트의 ChatHandler 객체를 chatRoom에서 제거
chatRoom.remove(key);
- 생성된 고유 키를 사용하여 chatRoom 맵에서 해당 키에 해당하는 ChatHandler 객체를 제거한다.
- chatRoom은 Map<String, ChatHandler> 타입으로, 클라이언트의 고유 키와 해당 클라이언트의 ChatHandler 객체를 저장한다.
3. 클라이언트 퇴장 메시지 출력
System.out.println("퇴장 : " + key);
- 클라이언트가 채팅방에서 퇴장했음을 알리는 메시지를 콘솔에 출력한다.
- 퇴장 메시지에는 클라이언트의 고유 키가 포함된다.
4. 현재 채팅자 수 출력
System.out.println("현재 채팅자 수 : " + chatRoom.size() + "\n");
- 현재 채팅방에 있는 클라이언트 수를 콘솔에 출력한다.
- chatRoom.size()를 사용하여 현재 맵에 저장된 ChatHandler 객체의 수를 가져온다.
- sendToAll 메서드는 모든 클라이언트에게 메시지를 전송하는 기능을 합니다. 이 메서드는 메시지를 JSON 형식으로 변환한 후, 모든 클라이언트에게 전송합니다. 이 과정에서 메시지를 보낸 클라이언트는 제외합니다.
//모든 클라이언트에게 메시지 전송
public void sendToAll(ChatHandler sender, String message) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("clientIp", sender.clientIp);
jsonObject.put("chatName", sender.chatName);
jsonObject.put("message", message);
String json = jsonObject.toString(); //JSONObject -> String 변환
Collection<ChatHandler> collection = chatRoom.values();
for(ChatHandler chatHandler : collection) {
if(chatHandler == sender) //메시지를 보낸 ChatHandler는 제외
continue;
chatHandler.send(json);
}
}
sendToAll 메서드의 역할
- JSON 객체 생성 및 데이터 추가
- JSON 객체를 문자열로 변환
- 모든 클라이언트에게 메시지 전송
1. JSON 객체 생성 및 데이터 추가
JSONObject jsonObject = new JSONObject();
jsonObject.put("clientIp", sender.clientIp);
jsonObject.put("chatName", sender.chatName);
jsonObject.put("message", message);
- 새로운 JSONObject 객체를 생성한다.
- 이 객체에 메시지를 보낸 클라이언트의 IP 주소(clientIp), 이름(chatName), 그리고 메시지 내용을 추가한다.
- 이 과정을 통해 전송할 메시지를 구조화된 JSON 형식으로 만든다.
2. JSON 객체를 문자열로 변환
String json = jsonObject.toString(); // JSONObject -> String 변환
- 생성한 JSONObject 객체를 문자열로 변환한다.
- 이는 전송하기 전에 메시지를 문자열 형식으로 변환하여 네트워크를 통해 전송할 수 있도록 하기 위함이다.
3. 모든 클라이언트에게 메시지 전송
Collection<ChatHandler> collection = chatRoom.values();
for (ChatHandler chatHandler : collection) {
if (chatHandler == sender) // 메시지를 보낸 ChatHandler는 제외
continue;
chatHandler.send(json);
}
- chatRoom 맵의 모든 ChatHandler 객체를 Collection으로 가져온다.
- 반복문을 통해 각 ChatHandler 객체에 접근한다.
- 메시지를 보낸 클라이언트(sender)는 제외하고, 나머지 모든 클라이언트에게 메시지를 전송한다.
- 각 ChatHandler 객체의 send 메서드를 호출하여 메시지를 전송한다.
//서버 종료
private void stop() {
try {
serverSocket.close();//서버 종료
threadPool.shutdown();//threadPool도 막아버렸다.
//chatRoom에 있는 모든 ChatHandler를 닫는다.
//chatRoom.values()로 Collection<ChatHandler>를 얻고, 요소 스트림을 이용해서 전체 ChatHandler의 close()를 호출
chatRoom.values().stream().forEach(sc -> sc.close());
System.out.println("서버 종료");
}catch(IOException e) {
//e.printStackTrace();
}
}//stop()
stop 메서드의 역할
- 서버 소켓 닫기
- 스레드 풀 종료
- 모든 ChatHandler 닫기
- 종료 메시지 출력
1. 서버 소켓 닫기
serverSocket.close(); // 서버 종료
- ServerSocket 객체를 닫는다.
- 이를 통해 서버는 더 이상 새로운 클라이언트 연결 요청을 수락하지 않는다.
2. 스레드 풀 종료
threadPool.shutdown(); // threadPool도 막아버렸다.
- ExecutorService의 shutdown 메서드를 호출하여 스레드 풀을 종료한다.
- 이는 더 이상 새로운 작업을 받아들이지 않으며, 현재 실행 중인 작업이 완료될 때까지 기다린다.
3. 모든 ChatHandler 닫기
// chatRoom에 있는 모든 ChatHandler를 닫는다.
// chatRoom.values()로 Collection<ChatHandler>를 얻고, 요소 스트림을 이용해서 전체 ChatHandler의 close()를 호출
chatRoom.values().stream().forEach(sc -> sc.close());
- chatRoom 맵의 모든 ChatHandler 객체를 가져온다.
- stream을 사용하여 각 ChatHandler 객체의 close 메서드를 호출한다.
- 이는 각 클라이언트와의 연결을 안전하게 종료한다.
4. 종료 메시지 출력
System.out.println("서버 종료");
- 서버가 정상적으로 종료되었음을 알리는 메시지를 콘솔에 출력한다.
public static void main(String[] args) {
try {
ChatServer chatServer = new ChatServer();
chatServer.start();// 서버 시작하는 거
System.out.println();
System.out.println("서버를 종료하려면 q를 입력하세요");
System.out.println();
Scanner scan = new Scanner(System.in);
while(true) {
String key = scan.nextLine();
if(key.toLowerCase().equals("q"))
break;
}
scan.close();
chatServer.stop(); // 서버 정지시키는 거
}catch(IOException e) {
e.printStackTrace();
System.out.println("[서버] " + e.getMessage());
}
}
}
ChatServer chatServer = new ChatServer();:
- ChatServer 클래스의 새 인스턴스를 생성한다. 이 클래스는 채팅 서버의 기능을 구현하는 클래스이다.
ChatHandler.java
package network;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import org.json.JSONObject;
public class ChatHandler {
ChatServer chatServer; //서버 인스턴스
Socket socket; //클라이언트 소켓
DataInputStream dis; // 클라이언트와의 데이터 통신을 위한 입력 스트림
DataOutputStream dos; // 클라이언트와의 데이터 통신을 위한 출력 스트림
String chatName; //클라이언트의 닉네임
String clientIp; //클라이언트의 IP 주소
- 이 코드는 ChatHandler 클래스의 생성자로, 채팅 서버와 클라이언트 간의 통신을 초기화한다. 생성자 내부에서 입력 및 출력 스트림을 설정하고, 클라이언트의 IP 주소를 얻으며, 데이터를 수신하는 메서드를 호출한다.
public ChatHandler(ChatServer chatServer, Socket socket) throws IOException {
this.chatServer = chatServer;
this.socket = socket;
//IO생성
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress(); // 클라이언트의 주소
clientIp = isa.getHostName();
receive();
}
public ChatHandler(ChatServer chatServer, Socket socket) throws IOException {
- 이 생성자는 ChatHandler 클래스의 객체를 생성할 때 호출된다. ChatServer 인스턴스와 Socket 인스턴스를 매개변수로 받는다.
this.chatServer = chatServer;
this.socket = socket;
- this.chatServer = chatServer;:
- 전달받은 ChatServer 인스턴스를 chatServer 멤버 변수에 할당한다. 이를 통해 이 핸들러가 속한 서버를 참조할 수 있다.
- this.socket = socket;:
- 전달받은 Socket 인스턴스를 socket 멤버 변수에 할당한다. 이를 통해 클라이언트와의 통신 소켓을 설정한다.
// IO 생성
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
- dis = new DataInputStream(socket.getInputStream());:
- 소켓의 입력 스트림을 래핑하여 DataInputStream 객체를 생성합니다. 이를 통해 클라이언트로부터 데이터를 읽을 수 있습니다.
- dos = new DataOutputStream(socket.getOutputStream());:
- 소켓의 출력 스트림을 래핑하여 DataOutputStream 객체를 생성합니다. 이를 통해 클라이언트로 데이터를 보낼 수 있습니다.
InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress(); // 클라이언트의 주소
clientIp = isa.getHostName();
- InetSocketAddress isa = (InetSocketAddress) socket.getRemoteSocketAddress();:
- 소켓의 원격 주소를 InetSocketAddress 객체로 캐스팅하여 얻습니다. 이는 클라이언트의 주소 정보를 포함합니다.
- clientIp = isa.getHostName();:
- 원격 주소에서 호스트 이름(IP 주소)을 가져와 clientIp 멤버 변수에 할당합니다. 이를 통해 클라이언트의 IP 주소를 확인할 수 있습니다.
receive();
- receive 메서드를 호출하여 클라이언트로부터 데이터를 수신하는 작업을 시작합니다. 이 메서드는 데이터를 읽고 처리하는 기능을 할 것입니다.
//클라이언트로부터 오는 JSON 데이터 받기
public void receive() {
chatServer.threadPool.execute(() -> {
try {
while(true) {
String receiveJSON = dis.readUTF();
JSONObject jsonObject = new JSONObject(receiveJSON);
String command = jsonObject.getString("command");
switch(command) {
case "enter":
this.chatName = jsonObject.getString("data");
chatServer.sendToAll(this, "입장하셨습니다.");
chatServer.addSocketClient(this);
break;
case "message":
String message = jsonObject.getString("data");
chatServer.sendToAll(this, message);
break;
}
}//while
}catch(IOException e) {
chatServer.sendToAll(this, "퇴장하셨습니다.");
chatServer.removeSocketClient(this);
}
});
}
//클라이언트로 JSON 데이터 보내기
public void send(String json) {
try {
dos.writeUTF(json);
dos.flush();
} catch (IOException e) {
//e.printStackTrace();
}
}
public void close() {
try {
socket.close();
}catch(IOException e) {
//e.printStackTrace();
}
}
}
ChatClient.java
package network;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import org.json.JSONObject;
public class ChatClient {
Socket socket; //서버와의 연결을 위한 소켓
DataInputStream dis; //서버와의 데이터통신을 위한 스트림
DataOutputStream dos;
String chatName; //클라이언트의 닉네임
//서버에 연결
private void connect() throws UnknownHostException, IOException {
socket = new Socket("localhost", 9500); //서버IP, Port번호
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
System.out.println("서버에 연결되었음");
}
//서버로부터 JSON 데이터 받기
public void receive() {
Thread thread = new Thread(() -> {
try {
while(true) {
String json = dis.readUTF(); //서버와 통신이 끊어지면 IOException 발생
JSONObject jsonObject = new JSONObject(json);
String clientIp = jsonObject.getString("clientIp");
String chatName = jsonObject.getString("chatName");
String message = jsonObject.getString("message");
System.out.println("[" + chatName + "@" + clientIp + "]" + message);
}//while
}catch(IOException e) {
System.out.println("서버와 연결이 끊어졌음.");
System.exit(0);
}
});
thread.start();
}
//서버로 데이터 JSON 보내기 - main메소드에서 키보드로부터 입력한 메시지를 보낼 때 호출
public void send(String json) throws IOException {
dos.writeUTF(json);
dos.flush();
}
public void unconnect() throws IOException {
socket.close();
}
//클라이언트 프로그램을 시작하고 메시지를 주고받는다.
public static void main(String[] args) {
try {
ChatClient chatClient = new ChatClient();
chatClient.connect();
Scanner scan = new Scanner(System.in);
System.out.print("닉네임 입력 : ");
chatClient.chatName = scan.next();
JSONObject jsonObject = new JSONObject();
jsonObject.put("command", "enter");
jsonObject.put("data", chatClient.chatName);
String json = jsonObject.toString();
chatClient.send(json);//서버로 보내고
//----------------------
chatClient.receive();//서버로부터 오는 내용 받고
System.out.println();
System.out.println("메시지를 입력하세요.");
System.out.println("클라이언트를 종료하려면 q를 입력하세요");
System.out.println();
while(true) {
String message = scan.nextLine();
if(message.toLowerCase().equals("q")) {
break;
}else {
jsonObject = new JSONObject();
jsonObject.put("command", "message");
jsonObject.put("data", message);
json = jsonObject.toString();
chatClient.send(json);
}
}//while
scan.close();
chatClient.unconnect();
}catch (IOException e) {
System.out.println("서버와 연결이 안됨");
}
}
}
'JAVA' 카테고리의 다른 글
DAY 16 - LOMBOK / 시퀀스 객체 / JDBC / DB 연결 (2024.07.24) (0) | 2024.08.09 |
---|---|
DAY 17 - MEMBER (2024.07.25) (0) | 2024.08.08 |
DAY 19 - Lambda (2024.07.29) (0) | 2024.08.07 |
DAY 20 - Network (2024.07.30) (0) | 2024.08.07 |
DAY 21 - Stream (2024.07.31) (0) | 2024.08.06 |