- SocketCloseUtil
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import static util.MyLogger.log;
public class SocketCloseUtil {
public static void closeAll(Socket socket, InputStream input, OutputStream output) {
close(input);
close(output);
close(socket);
}
public static void close(InputStream input) {
if (input != null) {
try {
input.close();
} catch (IOException e) {
log(e.getMessage());
}
}
}
public static void close(OutputStream output) {
if (output != null) {
try {
output.close();
} catch (IOException e) {
log(e.getMessage());
}
}
}
public static void close(Socket socket) {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
log(e.getMessage());
}
}
}
}
- ClientV6
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
import static util.MyLogger.log;
public class ClientV6 {
private static final int PORT = 12345;
public static void main(String[] args) throws IOException {
log("클라이언트 시작");
try(Socket socket = new Socket("localhost", PORT);
DataInputStream input = new DataInputStream(socket.getInputStream());
DataOutputStream output = new DataOutputStream(socket.getOutputStream())) {
log("소캣 연결: " + socket);
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("전송 문자: ");
String toSend = scanner.nextLine();
// 서버에게 문자 보내기
output.writeUTF(toSend);
log("client -> server: " + toSend);
if (toSend.equals("exit")) {
break;
}
// 서버로부터 문자 받기
String received = input.readUTF();
log("client <- server: " + received);
}
} catch (IOException e) {
log(e);
}
}
}
- ServerV6
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import static util.MyLogger.log;
public class ServerV6 {
private static final int PORT = 12345;
public static void main(String[] args) throws IOException {
log("서버 시작");
SessionManagerV6 sessionManager = new SessionManagerV6();
ServerSocket serverSocket = new ServerSocket(PORT);
log("서버 소켓 시작 - 리스닝 포트: " + PORT);
// ShutdownHook 등록
ShutdownHook shutdownHook = new ShutdownHook(serverSocket, sessionManager);
Runtime.getRuntime().addShutdownHook(new Thread(shutdownHook, "shutdown"));
try {
while (true) {
Socket socket = serverSocket.accept(); // 블로킹
log("소켓 연결: " + socket);
SessionV6 session = new SessionV6(socket, sessionManager);
Thread thread = new Thread(session);
thread.start();
}
} catch (IOException e) {
log("서버 소켓 종료: " + e);
}
}
static class ShutdownHook implements Runnable {
private final ServerSocket serverSocket;
private final SessionManagerV6 sessionManager;
public ShutdownHook(ServerSocket serverSocket, SessionManagerV6 sessionManager) {
this.serverSocket = serverSocket;
this.sessionManager = sessionManager;
}
@Override
public void run() {
log("shutdownHook 실행");
try {
sessionManager.closeAll();
serverSocket.close();
Thread.sleep(1000); // 자원 정리 대기
} catch (Exception e) {
e.printStackTrace();
System.out.println("e = " + e);
}
}
}
}
- SessionManagerV6
import java.util.ArrayList;
import java.util.List;
// 동시성 처리
public class SessionManagerV6 {
private List<SessionV6> sessions = new ArrayList<>();
public synchronized void add(SessionV6 session) {
sessions.add(session);
}
public synchronized void remove(SessionV6 session) {
sessions.remove(session);
}
public synchronized void closeAll() {
for (SessionV6 session : sessions) {
session.close();
}
sessions.clear();
}
}
- SessionV6
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import static network.tcp.SocketCloseUtil.*;
import static util.MyLogger.log;
public class SessionV6 implements Runnable {
private final Socket socket;
private final DataInputStream input;
private final DataOutputStream output;
private final SessionManagerV6 sessionManager;
private boolean closed = false;
public SessionV6(Socket socket, SessionManagerV6 sessionManager) throws IOException {
this.socket = socket;
this.input = new DataInputStream(socket.getInputStream());
this.output = new DataOutputStream(socket.getOutputStream());
this.sessionManager = sessionManager;
this.sessionManager.add(this);
}
@Override
public void run() {
try {
while (true) {
// 클라이언트로부터 문자 받기
String received = input.readUTF();
log("client -> server: " + received);
if (received.equals("exit")) {
break;
}
// 클라이언트에게 문자 보내기
String toSend = received + " World!";
output.writeUTF(toSend);
log("client <- server: " + toSend);
}
} catch (IOException e) {
log(e);
} finally {
sessionManager.remove(this);
close();
}
}
// 세션 종료시, 서버 종료시 동시에 호출될 수 있다.
public synchronized void close() {
if (closed) {
return;
}
closeAll(socket, input, output); // shutdown
closed = true;
log("연결 종료: " + socket);
}
}
'개발이 좋아서 > Java가 좋아서' 카테고리의 다른 글
네트워크 예외2 - 타임아웃 (0) | 2024.11.30 |
---|---|
네트워크 예외1 - 연결 예외 (1) | 2024.11.30 |
네트워크 - 자원 정리(try-with-resources) (0) | 2024.11.28 |
네트워크 - 인터넷 통신 / IP(Internet Protocol) / TCP, UDP / PORT / DNS (0) | 2024.11.27 |
파일 복사 최적화 (0) | 2024.11.27 |