소켓 이론 1/3 · 완전 기초

소켓은 프로그램 두 개를 잇는 통신 창구입니다.

서버가 기다리고, 클라이언트가 IP와 포트로 찾아가 연결합니다. 그다음 문자열이 바이트가 되어 왕복하고, 대화가 끝나면 연결을 닫습니다. 함수 이름보다 먼저 이 한 흐름을 눈으로 익혀 보세요.

이것만 기억하세요IP는 컴퓨터,
포트는 프로그램
socket = 데이터를 읽고 쓰는 창구

한 번의 대화를 따라가세요

“안녕하세요”는 서버까지 어떻게 갈까요?

읽는 순서① 조건 선택② 통신 시작③ 주황색 설명과 움직이는 바이트 확인

어디로 연결할까요?
무엇을 보낼까요?
  1. 1서버 대기포트를 열어요
  2. 2목적지IP + 포트
  3. 3연결통로를 만들어요
  4. 4요청바이트를 보내요
  5. 5응답답장을 받아요
  6. 6종료통로를 닫아요
접속할 주소
IP · 컴퓨터127.0.0.1
PORT · 프로그램8080
CLIENT PROGRAM클라이언트127.0.0.1
대화 소켓아직 없음
받은 응답비어 있음
LOOPBACK
아직 연결되지 않음
SERVER PROGRAM서버127.0.0.1
듣는 소켓서버 시작 전
대화 소켓아직 없음
받은 요청비어 있음
시작 전
이 흐름을 실제 소켓 함수와 연결해 보기
SERVERsocket → bind(8080) → listen → accept

포트에서 기다리다가 연결된 대화 소켓을 하나 받습니다.

CLIENTsocket → connect(127.0.0.1:8080)

IP와 포트로 서버를 찾아가 연결된 소켓을 만듭니다.

BOTHsend / recv → close

연결된 소켓에서 바이트를 주고받고 대화가 끝나면 닫습니다.

처음엔 세 단어만

주소와 통신 창구를 구분하세요.

IP어느 컴퓨터인가?

네트워크에서 목적 컴퓨터를 찾는 주소입니다. `127.0.0.1`은 지금 이 컴퓨터 자신을 가리킵니다.

PORT그 안의 어느 프로그램인가?

한 컴퓨터 안에서 서버 프로그램을 구분하는 번호입니다. 이 데모의 서버는 `8080`번을 사용합니다.

SOCKET코드가 데이터를 읽고 쓰는 창구

운영체제가 제공하는 통신 객체입니다. 연결 뒤 프로그램은 이 창구에 바이트를 쓰고 여기서 읽습니다.

통신 방식도 정합니다

이 데모는 TCP 소켓입니다.

TCP먼저 연결하고, 순서대로 전달

빠진 데이터는 다시 보내고 순서를 맞춥니다. 웹·채팅·데이터베이스 연결처럼 정확한 전달이 중요한 곳에 씁니다.

UDP연결 없이, 메시지를 바로 전달

손실·순서 변경 가능성을 애플리케이션이 감당합니다. 실시간 음성·게임·DNS처럼 지연을 줄이고 싶은 곳에 씁니다.

서버가 포트에서 대기클라이언트가 IP:포트로 연결바이트를 양방향으로 교환연결 종료
한 번의 TCP 대화를 단순화한 학습용 시뮬레이션입니다.

실제 TCP 아래에서는 3-way handshake, 패킷 분할, 재전송과 종료 절차가 더 일어납니다. TCP는 바이트 스트림이므로 프로그램이 메시지 길이·구분자 같은 경계를 따로 정해야 하며, 운영 서버에는 timeout, backpressure, 동시 연결 처리와 오류 복구도 필요합니다.

이 데모에 대하여

소켓 하나가 열리고 닫히는 순서를 따라갑니다

이 화면은 양쪽 소켓의 상태와 회선의 상태를 각각 따로 들고 있습니다. 기다리기 · 주소 정하기 · 연결하기 · 요청 · 응답 · 닫기라는 여섯 단계를 지나는 동안, 클라이언트 쪽과 서버 쪽이 서로 다른 상태에 있는 구간이 계속 생깁니다. 소켓을 처음 다룰 때 헷갈리는 것 대부분이 이 어긋남에서 나오기 때문에, 하나의 연결을 두 개의 상태로 나눠 보여주는 것이 이 화면의 목적입니다.

  1. 접속할 곳을 같은 PC 안과 같은 네트워크 안 중에서 골라 봅니다.
  2. 고른 선택에 따라 양쪽 주소가 어떻게 달라지는지 확인합니다.
  3. 서버 쪽이 먼저 듣기 상태로 들어가는 단계를 봅니다.
  4. 연결 단계에서 클라이언트 소켓의 상태가 어떻게 바뀌는지 따라갑니다.
  5. 요청을 보낼 때 실제 바이트 수와 16진수 미리보기를 확인합니다.
  6. 응답이 돌아오는 방향에서 같은 연결이 그대로 쓰이는지 봅니다.
  7. 닫기 단계에서 양쪽이 각각 어떤 상태가 되는지 비교합니다.
  8. 메시지를 바꿔 다시 실행하고 바이트 수가 함께 달라지는지 확인합니다.
  9. 한글이 섞인 내용에서 글자 수와 바이트 수가 다른지 확인합니다.
  10. 듣기 상태 표시가 연결 뒤에도 그대로 켜져 있는지 봅니다.
  11. 요청과 응답이 같은 회선 표시 위에서 오가는지 확인합니다.

화면이 상태로 표현하는 것

01

듣는 소켓과 대화하는 소켓은 다릅니다.

서버 쪽에는 연결을 기다리는 소켓과 실제로 대화를 주고받는 소켓이 따로 있습니다. 화면에서 듣기 상태 표시와 서버 소켓 상태 표시를 나눠 둔 이유가 이것인데, 기다리는 쪽은 연결이 들어와도 계속 기다리는 상태로 남아 다음 손님을 받습니다. 서버 하나가 여러 접속을 동시에 처리할 수 있는 것이 이 구조 덕분입니다.

02

주소는 두 값이 한 쌍입니다.

연결을 지정하려면 어느 컴퓨터인지와 그 안의 어느 프로그램인지가 함께 필요합니다. 접속할 곳을 바꾸면 앞의 값만 달라지고 뒤의 번호는 그대로인 것을 화면에서 볼 수 있습니다. 같은 PC 안에서 붙을 때 쓰는 주소는 밖으로 나가지 않고 자기 자신을 가리키는 특별한 값이라, 네트워크가 없어도 동작합니다.

03

보내는 것은 글자가 아니라 바이트입니다.

화면은 보낼 내용의 바이트 수와 앞부분의 16진수 표현을 함께 보여줍니다. 소켓이 다루는 것은 사람이 읽는 문자열이 아니라 바이트 나열이고, 한글처럼 한 글자가 여러 바이트인 문자를 넣으면 글자 수와 바이트 수가 달라집니다. 길이를 글자 수로 계산했다가 어긋나는 문제가 여기서 시작됩니다.

04

연결은 한 번 열고 계속 씁니다.

요청과 응답이 같은 연결 위에서 오갑니다. 응답을 받기 위해 새로 연결을 열지 않으며, 회선 상태 표시가 그 사이에 끊기지 않는 것으로 이 점을 보여줍니다. 요청마다 연결을 새로 여는 방식과 비교하면 처음 여는 비용을 한 번만 치르게 되고, 그 차이가 잦은 통신에서 크게 벌어집니다.

05

닫는 것도 절차입니다.

마지막 단계에서 양쪽 소켓이 닫힌 상태로 바뀝니다. 프로그램을 그냥 종료해 버리면 상대는 연결이 왜 끊겼는지 알 수 없고, 정리되지 않은 자원이 남습니다. 닫기를 별도 단계로 둔 이유는 이것이 생략해도 되는 마무리가 아니라 대화의 일부이기 때문입니다.

06

상태 이름을 그대로 노출합니다.

연결 중 · 연결됨 · 보내는 중 · 받는 중 · 닫힘 같은 표시는 실제 프로그래밍에서 마주치는 소켓의 상태에 대응합니다. 코드에서 어느 함수를 부를 수 있는 시점인지가 이 상태로 정해지기 때문에, 화면에서 상태 변화를 눈으로 익혀 두면 코드의 호출 순서를 이해하기 쉬워집니다.

07

계산과 화면을 분리했습니다.

여섯 단계의 상태 변화는 화면 코드가 아니라 별도 모듈이 계산하고, 자동 테스트가 각 단계의 상태 조합을 확인합니다. 조작할 수 있는 선택지가 여럿이라 조합마다 결과가 달라지는데, 계산을 따로 떼어 두면 화면을 고치다가 특정 조합만 조용히 틀어지는 일을 막을 수 있습니다.

08

먼저 준비된 쪽이 기다립니다.

서버가 듣기 시작하기 전에 클라이언트가 연결을 걸면 거절당합니다. 화면에서 서버 쪽 준비 단계가 항상 먼저 오는 것은 이 순서가 지켜져야 하기 때문이고, 개발 중에 서버를 띄우기 전에 클라이언트를 실행해 연결 거부를 만나는 일이 흔합니다. 이때 나오는 오류는 주소를 잘못 적었을 때와 다르므로, 두 경우를 구분해 읽을 수 있으면 원인을 빨리 좁힐 수 있습니다.

09

같은 PC 안에서도 소켓입니다.

접속할 곳을 같은 PC 안으로 골라도 절차는 하나도 줄어들지 않습니다. 주소만 자기 자신을 가리키는 값으로 바뀔 뿐 듣고 연결하고 주고받고 닫는 순서는 그대로입니다. 개발할 때 대부분 이 방식으로 시험하기 때문에, 네트워크를 건너는 경우와 같은 코드가 그대로 동작한다는 점을 여기서 확인해 두면 나중에 헷갈리지 않습니다.

가장 단순한 한 번의 대화만 다룹니다.

브라우저는 실제로 어떤 소켓도 열지 않으며 화면의 모든 값은 계산해 만든 것입니다. 다루는 것은 클라이언트 하나와 서버 하나가 한 번 주고받고 끝나는 경우이고, 여러 클라이언트가 동시에 붙는 상황, 한 연결 위에서 요청을 여러 번 이어 보내는 경우, 상대가 응답 없이 사라졌을 때의 처리, 연결이 예상보다 오래 유지될 때 필요한 확인 신호는 나오지 않습니다. 또한 실제 소켓은 보낸 바이트가 상대 프로그램에 그대로 한 덩어리로 도착한다고 보장하지 않아서 경계를 직접 정해야 하는데, 이 화면은 메시지 하나가 한 번에 오가는 것으로 단순화했습니다. 그 문제는 파일 전송을 다루는 편에서 따로 확인할 수 있습니다. 또한 실제 코드에서는 연결이 끊겼을 때와 상대가 응답하지 않을 때의 처리가 대부분의 분량을 차지하는데, 이 화면은 모든 것이 잘 되는 경우만 보여줍니다.

참고 자료man7 — connect(2) 연결 시작man7 — listen(2) 연결 대기RFC 9293 — Transport Control Protocol

실험을 마쳤다면