[CS] Socket Communication

2025. 9. 26. 01:48·CS

오늘은 네트워크 프로그래밍에서 중요한 소켓 통신(Socket Communication)에 대해 알아보겠습니다.

 

먼저 소켓 통신이 무엇인지 간단히 살펴본 뒤, 네트워크에서 통신이 성립되는 과정인 TCP 3-way Handshake 절차를 설명드리겠습니다. 이어서 소켓 통신에서 Client와 Server의 역할과 흐름이 어떻게 구분되는지 살펴본 후, Java에서 이를 구현하는 예제를 통해 구체적인 통신 과정을 정리해 보겠습니다.

소켓 통신 (Socket Communication)

  • 네트워크에서 두 컴퓨터 간의 실시간 양방향 통신을 제공하는 기술
  • 양방향 통신: 상호 간의 데이터를 송수신하는 기술
  • 두 컴퓨터 간에 IP주소 + 포트번호의 조합으로 네트워크 간의 연결을 수행하며 수신자는 데이터를 요청하면 서버에서 응답을 제공해 주는 구조로 데이터를 송수신할 수 있습니다.

소켓 통신 관련 개념

용어 설명
패킷(Packet) 네트워크를 통해 전송되는 데이터의 기본 단위 (출발지, 목적지 정보, 전송되는 데이터)
소켓(Socket) 네트워크를 통해 데이터(패킷)를 전송하기 위한 통로
채널(Channel) 서버와 클라이언트 간에 데이터를 주고 받는 전송 경로, 이 채널을 통해 데이터는 송신자에서 수신자로 전달되며, 데이터의 전송방향(일방향 또는 양방향)과 전송 모드에 따라 구분
클라이언트(Client) 데이터를 요청하는 측으로 서버와 연결을 하여 서버로부터 데이터를 받아들이는 역할을 수행
서버(Server) 데이터를 요청 받아 클라이언트에게 전송하는 역할 수행
TCP(Transmission Control Protocol) 연결 지향적인 프로토콜, 데이터를 전송하기 전에 송신자와 수신자 간의 연결을 설정합니다.
UDP(User Datagram Protocol) 비연결 지향적인 프로토콜, 패킷을 수신자에게 보내고 패킷이 정확하게 도착했는지 확인하지 않습니다. (TCP보다 속도가 빠르지만, 패킷 순서나 손실에 대한 보장이 없어 신뢰도가 낮습니다.)
HandShake 각각의 네트워크에서 연결을 설정하는 단계, 통신이 시작되기 전에 두 장치 사이에 통신 세션을 설정하고 서로 데이터 전송을 준비하는 과정

 

 

소켓 통신의 정의와 사용되는 개념에 대해 알아보았으니, 이제 네트워크 연결 수립을 위한 TCP 3 way handshake 과정과 Client-Server 간 어떻게 통신이 이루어지는 지에 대해서 상세히 설명드리겠습니다. 연결 종료 과정의 TCP 4 way handshake 과정은 생략하도록 하겠습니다.

네트워크 연결: TCP 3 way handshake

  • 네트워크 연결을 설정하는 단계
  • SYN: 동기화 패킷으로 TCP 연결을 초기화하는 데 사용하며, 클라이언트가 서버에 연결을 시작하고자 할 때 보내는 패킷입니다.
  • SYN-ACK: 동기화 패킷에 대한 응답으로 SYN 패킷을 받은 서버가 클라이언트에게 보내는 패킷, 이 패킷을 통해 서버가 클라이언트의 연결 요청을 수락하고, 클라이언트와 서버 간의 연결이 성립됩니다.
  • ACK: 확인 패킷으로 데이터가 성공적으로 수신되었음을 보내는 측에 알리는 데 사용됩니다.

Client-Server 간 Socket Communication 과정

소켓 통신 과정

Client

TCP Client

 

  1. socket(): client socket 생성, 서버에 연결 요청을 보내기 위해서 사용합니다.
  2. connect(): 클라이언트가 생성한 소켓을 사용하여 서버에 연결 요청을 보냅니다. (TCP 3-way handshake)
  3. write(): 클라이언트에서 소켓을 통해 출발지, 목적지 IP, Port 정보와 데이터를 서버로 전송합니다.
  4. read(): 클라이언트 요청에 따른 서버의 응답 값을 전달받습니다.
  5. close(): 연결을 끊기 위해 FIN 패킷  (TCP 4-way handshake에서 사용되는 패킷)을 서버로 전송합니다.

Server

TCP Server

  1. socket(): 클라이언트의 연결 요청을 확인하기 위해 서버 소켓을 생성합니다.
  2. bind(): 생성한 소켓을 특정 IP와 포트번호에 연결합니다. 이 과정을 통해 외부의 연결 요청을 해당 서버의 IP 주소와 Port 번호로 받을 수 있게 됩니다.
  3. listen(): 클라이언트 요청을 기다립니다. (해당 과정에서 동시에 처리 가능한 연결 요청 수를 지정합니다.)
  4. accept(): 서버가 클라이언트의 요청을 수락합니다. 연결이 수락되면, 클라이언트와의 통신을 위한 새로운 소켓을 생성합니다.
  5. read(): 클라이언트로부터 데이터를 수신하고, 이를 잘 가공하여 응답을 생성합니다.
  6. write(): 클라이언트에게 데이터를 응답합니다.
  7. read(): 서버가 클라이언트의 추가 요청이나 응답을 읽습니다.
  8. close(): 소켓 통신을 종료합니다. (입출력 종료)

Java Socket Communication

  • java.net.ServerSocket
    • 클라이언트의 연결 요청을 기다리면서 요청이 들어왔을 때 수락 이후, 소켓을 생성합니다.
  • java.net.Socket
    • 연결된 클라이언트와의 통신을 담당합니다.
  • binding port: 클라이언트가 서버에 접속할 포트
    • 서버는 고정된 포트 번호에 바인딩해서 실행합니다.
  • 서버가 실행되면 클라이언트는 서버의 IP주소와 바인딩 포트번호로 Socket을 생성하여 연결을 요청합니다.
  • 이후, SocketSocket은 클라이언트가 연결 요청을 하면 accept() 메서드로 연결을 수락합니다.
  • BufferedReader/BufferedWriter, InputStreamReader, OutputStreamWriter
    • 소켓 통신에서 데이터 송수신을 위해 문자를 바이트로, 바이트를 문자로 변환하기 위한 클래스입니다.
    • 데이터 입출력의 효율을 높이기 위해 데이터를 바로 전달하기 않고, 버퍼를 활용하는 BufferedReader와 BufferedWriter와 함께 사용합니다.

 

이제 Client-Server 관점에서 Socket 통신 과정도 알아보았으니, Java에서 TCP Server, Client를 직접 구현한 코드를 보여드리겠습니다.  소스 코드에 대한 설명은 생략하고, 각 단계별로 주석을 남겼습니다.

 

Java Network Programming - Socket Communication

Server.class

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.logging.Logger;

public class Server implements Runnable {

    private static final Logger log = Logger.getLogger(Server.class.getName());
    private static final int PORT = 8000;
    private static final String QUIT_OPTION = "q";

    @Override
    public void run() {

        // 1. create serversocket (port binding)
        try(ServerSocket serverSocket = new ServerSocket(PORT)) {
            log.info("[Server]: create server socket(port binding), port number : " + PORT);

            // 2. wait client connection
            Socket socket = serverSocket.accept();
            log.info("[Client]: connected - IP address : " + socket.getRemoteSocketAddress());

            // 3. create inputstream, outputstream for data transmission/reception
            try(Socket s = socket; Scanner scanner = new Scanner(System.in);
                BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
                BufferedWriter out = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()))) {

                while(true) {
                    // 4. receive client message
                    String message = in.readLine();
                    log.info("[Server]: received message from client: " + message);

                    if(message.equalsIgnoreCase(QUIT_OPTION)) {
                        log.info("[Server]: quit server by client");
                        break;
                    }

                    log.info("[Server]: send message to client");

                    // 5. send server message
                    String sendMessage = scanner.nextLine();
                    out.write(sendMessage + "\n");
                    out.flush();

                    if (sendMessage.equalsIgnoreCase(QUIT_OPTION)) {
                        log.info("[Server]: request stop");
                        break;
                    }
                }
            }
        } catch (IOException e) {
            log.severe("I/O error occurred while socket connection");
            throw new RuntimeException(e);
        }
    }
}

Client.class

import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
import java.util.logging.Logger;

public class Client implements Runnable {

    private static final Logger log = Logger.getLogger(Client.class.getName());
    private static final String HOST = "127.0.0.1";
    private static final int PORT = 8000;
    private static final String QUIT_OPTION = "q";

    @Override
    public void run() {
        // 1. create client socket
        // 2. create inputstream, outputstream for data transmission/reception
        try(Socket socket = new Socket(HOST, PORT);
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            Scanner scanner = new Scanner(System.in)) {

            log.info("[Client]: connect to server - IP : " + HOST + ", port : " + PORT);

            while(true) {
                // 3. send client message
                log.info("[Client]: send message to server");

                String sendMessage = scanner.nextLine();

                if(sendMessage.equalsIgnoreCase(QUIT_OPTION)) {
                    log.info("[Client]: quit client socket communication");
                }

                out.write(sendMessage + "\n");
                out.flush();
                
                // 4. receive server message
                String message = in.readLine();
                log.info("[Client]: received message from server: " + message);

                if(!scanner.hasNextLine()) {
                    break;
                }
            }

        } catch (UnknownHostException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            log.severe("I/O error occurred while socket connection");
            throw new RuntimeException(e);
        }
    }
}

 

 

실행 결과

 

  • client가 server에게 메시지를 전송하게 되면, server는 client의 메시지를 전달받고 다시 회신할 수 있게 됩니다.
  • client, server가 "q"를 전달 및 전송하게 된다면, 소켓 통신이 종료되도록 구성하였습니다. 

 

<참고 자료>

 

https://adjh54.tistory.com/516

저작자표시 비영리 변경금지 (새창열림)

'CS' 카테고리의 다른 글

[CS] Concurrency, Parallelism  (0) 2025.09.24
[CS] Call by Value, Call by Reference  (1) 2025.08.31
[CS] clustered Index, non-clustered Index  (4) 2025.08.27
[Java] Functional Interface  (5) 2025.08.26
[CS] JVM Memory Structure  (6) 2025.08.15
'CS' 카테고리의 다른 글
  • [CS] Concurrency, Parallelism
  • [CS] Call by Value, Call by Reference
  • [CS] clustered Index, non-clustered Index
  • [Java] Functional Interface
SeungbeomKim
SeungbeomKim
[IT(PS, CS, SW, etc.) 지식 기록] Github : https://github.com/daily1313/
  • SeungbeomKim
    개발 블로그
    SeungbeomKim
  • 전체
    오늘
    어제
    • 분류 전체보기 (400)
      • 일상 (33)
        • 여행 (17)
        • 회고록 (9)
        • 리뷰 (7)
      • PS (138)
        • 그리디 알고리즘[Greedy] (25)
        • 정렬 알고리즘[Sort] (18)
        • 문자열 알고리즘[String] (14)
        • 동적 계획 알고리즘[DP] (17)
        • 깊이 우선 탐색, 너비 우선 탐색[DFS, BFS.. (34)
        • 재귀[Recursion] (2)
        • 백트래킹[Backtracking] (5)
        • 브루트포스 알고리즘[Bruteforce] (16)
        • 자료 구조[Data Structure] (4)
        • 분할 정복 알고리즘[Divide & Conquer.. (3)
      • CS (29)
      • Network (11)
      • Database (8)
        • Elasticsearch (3)
      • Linux (2)
      • JavaScript (4)
        • AngularJS (1)
      • Java (100)
        • Effective Java (9)
        • Java Concept (21)
        • Spring (61)
        • Design Pattern (4)
      • Python (2)
      • Vscode (1)
      • DevOps (44)
        • AWS (27)
        • Git (7)
        • Docker (7)
        • Nginx (1)
      • 자격증 (10)
        • SQL (4)
      • 사이드 프로젝트 (3)
        • MatJido (3)
      • 기타 (9)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 소개
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    너비 우선 탐색
    정보처리기사
    정보처리기사 실기
    dfs
    dp
    이펙티브 자바
    백트래킹
    다이나믹 프로그래밍
    springboot
    Wi-Fi
    AWS
    메타코딩
    일본여행
    sqld
    정보처리기사 필기
    docker
    컴퓨터구조
    Spring
    Effective Java
    BFS
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
SeungbeomKim
[CS] Socket Communication
상단으로

티스토리툴바