목차
개요
한양대학교 이석복 교수님의 네트워크 강의를 수강 중,
샘플 코드가 C 기반임에 따라 Java로 탐구하였음
TCP기반 소켓 통신 샘플 코드
=> ServerSocket/Socket 클래스 사용, UDP는 DatagramSocket 클래스 사용
C에서 Java로 바뀜에 따라, bind() 및 listen()을 할 필요가 없어졌음
=> ServerSocket이 서버용 소켓 클래스임에 따라 자동 수행
try-with-resources문 사용
=> 자동으로 socket.close() 수행
ServerSocket Class?
- 서버용으로 사용될 소켓 클래스 => Client는 Socket 클래스 사용
- Port는 Well-Known이여야 한다 => Client가 찾을 수 있어야 하므로
- new ServerSocket() 선언 시, Socket과 Server의 bind() 동작을 포함한다
bind(new InetSocketAddress(bindAddr, port), backlog);
In Source Code
서버 소켓을 생성하고 지정된 로컬 포트 번호에 바인딩하며, 지정된 백로그를 설정합니다. 포트 번호가 0이면, 포트 번호가 자동으로 할당됩니다. 일반적으로 임시 포트 범위에서 할당됩니다. 할당된 포트 번호는 getLocalPort 메서드를 호출하여 확인할 수 있습니다.
수신 대기 큐의 최대 길이는 백로그 파라미터로 설정됩니다. 큐가 가득 차면, 연결 요청이 도착했을 때 해당 연결 요청은 거부됩니다.
애플리케이션에서 서버 소켓 구현 팩토리를 지정한 경우, 그 팩토리의 createSocketImpl 메서드가 실제 소켓 구현을 생성하는 데 사용됩니다. 그렇지 않은 경우, 시스템 기본 소켓 구현이 생성됩니다.
보안 관리자가 존재하는 경우, 보안 관리자의 checkListen 메서드가 포트 번호를 인자로 호출되어 작업이 허용되는지 확인합니다. 이로 인해 SecurityException이 발생할 수 있습니다.
백로그 인자는 소켓에서 요청된 최대 대기 연결 수입니다. 이 값의 정확한 의미는 구현에 따라 다를 수 있습니다. 특히, 구현에 따라 최대 길이를 설정하거나 이 파라미터를 무시할 수도 있습니다. 제공된 값은 0보다 커야 합니다. 0 이하인 경우, 구현에 따라 기본값이 사용됩니다.
Candidates for new ServerSocket()
ServerSocket()
ServerSocket(SocketImpl impl)
ServerSocket(int port)
ServerSocket(int port, int backlog)
ServerSocket(int port, int backlog, InetAddress bindAddr)
Parameters
Port
- 포트 번호, 16비트를 사용하므로 0 ~ 65535(2^16 -1)까지 사용 가능
- 0 기입시 사용가능한 임의의 Port 할당
Backlog
- 요청 대기 큐의 최대 길이를 설정 => 최대 값은 OS마다 상이
- Default 50
if (backlog < 1)
backlog = 50;
SocketImpl
- Socket의 기본 구현 및 네트워크 소켓의 세부 동작 제어 클래스
InetAddress
- IP 주소를 표현하고, 해당 IP 주소와 관련된 네트워크 작업을 지원
- 호스트 이름(= Domain Name)과 IP 주소 간의 변환을 처리
Exceptions
IOException – 소켓을 열 때 I/O 오류가 발생한 경우.
SecurityException – SecurityManager가 존재하고, checkListen 메서드가 작업을 허용하지 않는 경우.
IllegalArgumentException – 포트 매개변수가 유효한 포트 값 범위(0에서 65535 사이)를 벗어난 경우.
SecurityManager?
- 애플리케이션의 보안 정책 매니저 클래스
- 일반적으로 SecurityManager 클래스의 하위 클래스에서 checkListen을 상속받아 구현
- System.setSecurityManager, JVM Options 등에 적용
Sample Code
1. Server Code
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
public class Server {
public static void main(String[] args) {
int port = 9999; // 서버가 수신 대기할 포트 번호
try (ServerSocket serverSocket = new ServerSocket()) {
System.out.println("Server is listening on port " + port);
// 클라이언트의 연결 요청을 수락
try (Socket clientSocket = serverSocket.accept()) {
System.out.println("Client connected!");
// 클라이언트로부터 메시지 수신
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = reader.readLine();
System.out.println("Received from client: " + message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. Client Code
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
String serverAddress = "localhost"; // 서버의 IP 주소 또는 호스트명
int port = 9999; // 서버의 포트 번호
try (Socket socket = new Socket(serverAddress, port)) {
System.out.println("Connected to server!");
// 서버로 메시지 전송
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("Hello, Server!");
writer.newLine(); // 메시지 끝을 표시하기 위해 줄 바꿈 추가
writer.flush(); // 데이터를 전송
} catch (IOException e) {
e.printStackTrace();
}
}
}