1:N 소켓 양방향 통신의 개념을 시각적으로 표현
+---------------------+ +---------------------+
| 서버 | | 클라이언트 1 |
| +---------------+ | | +---------------+ |
| | ServerSocket | | | | Socket | |
| +-------+-------+ | | +-------+-------+ |
| | | | | |
| v | | v |
| +-------+-------+ | | +-------+-------+ |
| | Socket[1] | |<--------->| | Network | |
| +-------+-------+ | | +---------------+ |
| | Socket[2] | | +---------------------+
| +-------+-------+ |
| | Socket[3] | | +---------------------+
| +-------+-------+ | | 클라이언트 2 |
| ... | | +---------------+ |
| +-------+-------+ | | | Socket | |
| | Socket[N] | |<--------->| +-------+-------+ |
| +---------------+ | | | |
+--------------------+ | v |
| +-------+-------+ |
| | Network | |
| +---------------+ |
+---------------------+
1단계 - MultiClient 처리 - 단 브로드캐싱은 안되는 상황 ← 서버측 코드 입니다.
package ch06;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
public class MultiClientServer {
private static final int PORT = 5000;
// 하나의 변수에 자원을 통으로 관리하기 기법 --> 자료구조
// 자료구조 ---> 코드 단일, 멀티 ---> 멀티 스레드 --> 자료 구조 ??
// 객체 배열 <-- Vector<> : 멀티 스레드에 안정적이다.
private static Vector<PrintWriter> clientWriters = new Vector<>();
//private static Set<PrintWriter> clientWriters = ConcurrentHashMap.newKeySet(); // 스레드 안전한 클라이언트 출력 스트림 집합
public static void main(String[] args) {
System.out.println("Server started....");
try (ServerSocket serverSocket = new ServerSocket(PORT)){
while(true) {
// 1. serverSocket.accept() 호출하면 블록킹 상태가 된다. 멈춰있음
// 2. 클라이언트가 연결 요청하면 새로운 소켓 객체 생성이 된다.
// 3. 새로운 스레드를 만들어 처리 ... (클라이언트가 데이터를 주고 받기 위한 스레드)
// 4. 새로운 클라이언트가 접속 하기 까지 다시 대기 유지(반복)
Socket socket = serverSocket.accept();
// 새로운 클라이언트가 연결 되면 새로운 스레가 생성된다.
new ClientHandler(socket).start();
}
} catch (Exception e) {
}
} // end of main
// 정적 내부 클래스 설계
private static class ClientHandler extends Thread {
private Socket socket;
private PrintWriter out;
private BufferedReader in;
public ClientHandler(Socket socket) {
this.socket = socket;
}
// 스레드 start() 호출시 동작 되는 메서드 - 약속
@Override
public void run() {
try {
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// 여기서 중요 ! - 서버가 관리하는 자료구조에 자원 저장(클,연결된 소켓->outStream)
clientWriters.add(out);
String message;
while( (message = in.readLine() ) != null ) {
System.out.println("Received : " + message);
broadcastMessage(message);
}
} catch (Exception e) {
//e.printStackTrace();
} finally {
try {
socket.close();
System.out.println("...... 클라이언트 연결 해제 ....... ");
} catch (IOException e) {
//e.printStackTrace();
}
}
}
} // end of ClientHandler
// 모든 클라이언트에게 메시지 보내기- 브로드캐스트
private static void broadcastMessage(String message) {
for(PrintWriter writer : clientWriters) {
writer.println(message);
}
}
}
Vector 클래스는 자바의 java.util 패키지에 포함된 동기화된 리스트 구현체입니다. Vector는 동기화된 메서드를 제공하여 멀티스레드 환경에서 안전하게 사용할수있습니다. 그러나 이러한 동기화 메서드는 성능에 영향을 미칠 수 있습니다.
import java.util.concurrent.ConcurrentHashMap;
public class ConcurrentHashMapExample {
public static void main(String[] args) {
// ConcurrentHashMap 생성
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 키-값 쌍 추가
map.put("one", 1);
map.put("two", 2);
map.put("three", 3);
// 값 가져오기
System.out.println("Value for 'one': " + map.get("one"));
System.out.println("Value for 'two': " + map.get("two"));
// 키 확인
System.out.println("Map contains key 'three': " + map.containsKey("three"));
// 값 제거
map.remove("two");
System.out.println("Map contains key 'two' after removal: " + map.containsKey("two"));
// 모든 키 출력
for (String key : map.keySet()) {
System.out.println("Key: " + key + ", Value: " + map.get(key));
}
}
}
'Java' 카테고리의 다른 글
소켓을 활용한 HTTP 통신 (0) | 2024.06.07 |
---|---|
제네릭(Generic) (0) | 2024.06.07 |
양방향 통신 (1) | 2024.06.07 |
Socket (0) | 2024.06.07 |
파일복사(문자기반 입/출력) (1) | 2024.06.04 |