[Java] Socket에 대하여
들어가기 전
이번 포스팅에서는 Socket이 무엇인지와 Http와의 차이점을 알아보고 예제를 만들어가면서 Socket에 대해서 알아보겠습니다.
Socket이란?
소켓은 네트워크 통신을 위한 양쪽 끝단을 의미합니다.
IP*와 Port*의 조합으로 통신을 위한 세션을 설정하고 데이터를 송수신하는 데 사용합니다.
통신을 위해서 서버와 클라이언트는 소켓을 생성하고 생성된 소켓 간에 통신하여 데이터를 송수신을 합니다.
서버 소켓은 하나만 생성할 수 있고 클라이언트 소켓은 여러 개 생성하여 하나의 서버에 연결하여 통신할 수 있습니다.
IP란?
IP 주소는 인터넷에 연결된 각 기기를 구별하기 위해 사용되는 고유한 번호입니다.
IP는 프로토콜 그 자체이고 IP주소는 IP통신을 하기 위해 각 기기들을 구분하는 고유번호라고 이해하면 됩니다.
IP 주소는 네트워크 내에서 특정 기기를 찾아 데이터를 전송할 수 있도록 도와주며, 기기들이 서로 통신할 때 필수적인 요소입니다.
Port란?
네트워크에서 하나의 IP 주소 안에서 실행되는 여러 프로세스(서비스)를 구별하기 위해 사용되는 논리적 통신 단위입니다.
즉, IP 주소는 컴퓨터(호스트)를 식별 포트 번호는 그 컴퓨터 안의 애플리케이션(프로세스)을 식별하기 위한 논리적 번호입니다.
예시
A동과 B동 아파트가 있고, 각 동에는 1·2·3·4호가 있다고 가정하겠습니다.
여기서 A동과 B동은 IP 주소, 1·2·3·4호는 포트 번호에 해당합니다.
즉, A동 1호, A동 2호처럼 각 세대는 자신의 동과 호수로 들어가 생활합니다.
A동, B동 = IP 주소→ 각각 하나의 건물(컴퓨터)을 의미합니다.
1, 2, 3, 4호 = 포트 번호
→ 건물 안에서 특정 세대(프로세스/서비스)를 구분하는 번호입니다.
Socket 통신
네트워크를 통해 두 프로그램(보통 서버와 클라이언트)이 소켓을 이용하여 데이터를 주고받는 통신방식을 말합니다.

위와 같은 과정을 통해 서버와 클라이언트가 소켓을 연결을 하고 통신을 합니다.
위 과정을 토대로 정상적으로 통신하는 경우와 그렇지 않은 경우에 대해서 알아보겠습니다.
정상 통신
클라이언트 소켓
1. socket() : 서버에 연결하기 위한 소켓 생성
2. connect() : 연결 요청 대기상태인 서버 소켓에 연결 요청
3. 연결 요청으로 인해 서버 소켓에서 응답이 오면 연결이 되어 Socket descriptor(소켓 자원을 식별하기 위한 번호)가 반환되고 데이터를 송수신할 준비
4. send() / recv() : 연결된 서버 소켓과 데이터 송수신
5. close() : 소켓 연결 종료
서버 소켓
1. socket() : 클라이언트와 통신하기 위한 준비용 소켓 생성(실제 통신이 이루어지지 않고 통신 대기용 소켓을 만드는 과정)
2. bind() : 생성한 소켓에 대해 Ip와 Port를 할당
3. listen() : 클라이언트의 연결 요청을 대기하는 상태로 전환
4. accept() : 클라이언트 측에서 연결 요청이 오면 수락 후 통신을 위한 소켓을 생성
5. send() / recv() : 연결된 클라이언트 소켓과 데이터 송수신
6. close() : 소켓 연결 종료
통신 순서
서버(socket()) -> 서버(bind()) -> 서버(listen()) -> 클라이언트(socket()) -> 클라이언트(connect()) ->
클라이언트(send() / recv()), 서버(send() / recv()) -> 클라이언트(close()), 서버(close())
연결 실패
클라이언트 소켓
1. socket() : 서버에 연결하기 위한 소켓 생성
2. connect() : 서버 소켓에서 bind 하여 할당받은 ip, port에 연결 요청
3. 서버 측 소켓에서 연결을 거부할 시 요청을 대기큐에 저장 -> 큐의 크기가 커지면 새로운 요청 거절
서버 소켓
1. socket() : 클라이언트와 통신하기 위한 준비용 소켓 생성(실제 통신이 이루어지지 않고 통신 대기용 소켓을 만드는 과정)
2. 생성한 소켓에 대해 Ip와 Port를 할당
3. listen() : 클라이언트의 연결 요청을 대기하는 상태로 전환
4. accept() : 클라이언트 측 요청 거절
통신 순서
서버(socket()) -> 서버(bind()) -> 서버(listen()) -> 클라이언트(socket()) -> 클라이언트(connect()) ->
서버(요청 거절) -> 요청 대기큐에 저장
지금까지 Socket에 대해서 알아보았습니다.
Socket 통신과 Http 통신의 차이점에 대해서 간단하게 알아보겠습니다.
Socket 통신 VS Http 통신
HTTP 통신은 TCP의 3-way handshake를 통해 서버와 클라이언트가 연결된 뒤 요청과 응답을 주고받습니다.
클라이언트가 요청한 데이터에 대해서 서버는 응답을 보내고 연결을 종료하는 단발성 통신 방식을 사용합니다.
반면 소켓 통신 역시 Http와 동일하게 TCP 기반이므로 3-way handshake를 통해 서버와 클라이언트가 연결합니다.
그런데 HTTP와 달리 서버가 클라이언트의 데이터를 한 번 처리했다고 해서 연결을 종료하지 않고 연결을 지속적으로 유지하면서 양방향으로 데이터를 계속 주고받을 수 있는 것이 특징입니다.
(참고 : 해당 포스팅은 소켓에 대해서 다루는 내용이라 Http, Tcp, 3-way handshake에 대해서는 자세히 알아보지 않습니다.)
소켓과 Http의 차이점에 대해서 알아보았습니다.
이제 Java를 활용하여 소켓을 생성, 연결, 통신하는 방법에 대해서 알아보겠습니다.
클라이언트 소켓
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
//클라이언트
public class ClientSocketEx {
public static void main(String[] args) throws IOException {
BufferedReader in = null;
PrintWriter out = null;
Scanner scanner = new Scanner(System.in);
try (Socket socket = new Socket("127.0.0.1", 8080);) { // -- 1. socket(), 2. connect()
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream());
while (true) {
System.out.print("전송하기>>> ");
String outputMessage = scanner.nextLine();
out.println(outputMessage); // 클라이언트 콘솔에 출력
out.flush(); // -- 4. send() 서버 소켓에 데이터 전송
if ("exit".equalsIgnoreCase(outputMessage)) {
break;
}
String inputMessage = in.readLine(); // -- 4. recv()
System.out.println("From Server: " + inputMessage);
if ("exit".equalsIgnoreCase(inputMessage)) {
break;
}
}
} catch (IOException e) {
System.out.println(e.getMessage());
} finally {
in.close();
out.close();
scanner.close(); // -- 5. close()
System.out.println("서버연결종료");
}
}
}
- Socket socket = new Socket("127.0.0.1", "8080") -> 클라이언트 소켓 생성, 서버 소켓에 연결 요청
- out.flush() -> 서버 소켓에 데이터 송신
- String inputMessage = in.readLine() -> 서버 소켓으로부터 데이터 수신
- try 구문에 선언되어 있는 Socket socket = new Socket("127.0.0.1", "8080") -> try-with-resource 구문으로 인해 try 문 끝나면 자동으로 자원해제하여 소켓 연결 종료
서버 소켓
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.Scanner;
public class ServerSocketEx {
public static void main(String[] args) throws IOException {
BufferedReader receiveMessageReader = null;
Scanner scanner = new Scanner(System.in);
PrintWriter out = null;
Socket acceptSocket = null;
// 1. socket():준비용 소켓 생성, 2. bind() : ip, port 할당, 3. listen() : 연결 요청을 받기 위한 대기 상태
try (ServerSocket serverSocket = new ServerSocket(8080)) {
System.out.println("연결 대기중 ..");
acceptSocket = serverSocket.accept(); // 4. accept() : 연결 소켓 생성
System.out.println("클라이언트 연결");
//5. recv() : 데이터 수신
receiveMessageReader = new BufferedReader(
new InputStreamReader(acceptSocket.getInputStream())); //5. recv
out = new PrintWriter(acceptSocket.getOutputStream());
while (true) {
String receiveMessage = receiveMessageReader.readLine();
if (receiveMessage.equalsIgnoreCase("exit")) {
break;
}
System.out.println("receive message: " + receiveMessage);
System.out.println("[Server] 전송 > ");
String sendMessage = scanner.nextLine();
out.println(sendMessage);
out.flush(); //5. send() : 데이터 송신
if ("quit".equalsIgnoreCase(sendMessage)) {
break;
}
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
receiveMessageReader.close();
scanner.close();
out.close();
acceptSocket.close(); //6. close() : 연결 종료
}
}
}
- ServerSocket serverSocket = new ServerSocket(8080) -> 서버 준비용 소켓 생성, ip, port 할당, 연결 요청을 받기 위해 대기상태 전환
- serverSocket.accept() : 클라이언트 연결 요청 수락 후 연결 소켓 생성
- receiveMessageReader = new BufferedReader(new InputStreamReader(acceptSocket.getInputStream())) : 클라이언트 데이터 수신
- out.flush : 클라이언트로 데이터 송신
- acceptSocket.close() -> 연결용 소켓 종료
- try 구문에 선언되어 있는 Socket socket = new ServerSocket("8080") -> try-with-resource 구문으로 인해 try 문 끝나면 자동으로 자원해제하여 소켓 연결 종료
'Java' 카테고리의 다른 글
| [Java] 함수형 인터페이스 (2) | 2025.08.02 |
|---|---|
| [Java] synchronized와 ReentrantLock에 대해서 (0) | 2025.03.14 |
| [Java] 동기화 기법에 대하여(뮤텍스, 세마포어) - 1 (0) | 2024.08.20 |
| [Java] 동시성 이슈 개념과 발생하는 동작 과정 (1) | 2024.07.26 |
| [Java] 스레드의 상태와 생명주기 (0) | 2024.07.23 |
댓글
이 글 공유하기
다른 글
-
[Java] 함수형 인터페이스
[Java] 함수형 인터페이스
2025.08.02 -
[Java] synchronized와 ReentrantLock에 대해서
[Java] synchronized와 ReentrantLock에 대해서
2025.03.14 -
[Java] 동기화 기법에 대하여(뮤텍스, 세마포어) - 1
[Java] 동기화 기법에 대하여(뮤텍스, 세마포어) - 1
2024.08.20 -
[Java] 동시성 이슈 개념과 발생하는 동작 과정
[Java] 동시성 이슈 개념과 발생하는 동작 과정
2024.07.26