[임베디드기사 실기 20부작 16편] TCP Socket, 3-Way/4-Way Handshake, UART와 SPI — 임베디드 통신의 핵심
임베디드 시스템에서 “통신”은 하나의 기술이 아닙니다. Linux 네트워크 프로그램에서는 TCP Socket을 사용하고, MCU와 센서·모듈 사이에서는 UART나 SPI를 사용합니다. 서로 다른 계층의 기술이지만 실기시험에서는 모두 데이터가 어디에서 어디로, 어떤 절차를 거쳐 이동하는가를 묻는다는 공통점이 있습니다.
이번 편에서는 TCP 서버의 socket() → bind() → listen() → accept() 흐름, TCP 연결 수립의 3-Way Handshake와 종료의 4-Way Handshake, 그리고 UART와 SPI의 물리적 통신 특성을 한 장 안에서 연결해 정리합니다.
TCP Socket은 운영체제의 네트워크 Stack을 이용해 원격 장치와 통신하는 인터페이스입니다.
UART / SPI는 MCU나 SoC가 주변 장치와 직접 데이터를 주고받기 위한 Hardware Interface입니다.
[ Application ]
│
├─ TCP Socket ─ Network Stack ─ Ethernet/Wi-Fi ─ Remote System
│
├─ UART ─ TX/RX ─ MCU / Modem / Serial Device
│
└─ SPI ─ SCLK/MOSI/MISO/CS ─ ADC / DAC / Sensor / Flash
시험에서는 이 세 기술을 서로 섞지 않고 “어느 계층의 통신인가”를 먼저 구분하는 것이 중요합니다.
Socket은 네트워크 통신을 위한 Endpoint입니다. Linux에서는 Socket도 File Descriptor 형태로 관리되기 때문에 일반 파일처럼 read(), write(), close()와 같은 인터페이스와 연결해서 이해할 수 있습니다.
TCP Server는 먼저 통신용 Socket을 생성하고, IP 주소와 Port를 지정한 뒤 연결 요청을 기다립니다.
실기에서 매우 자주 나오는 흐름은 다음과 같습니다.
socket() ↓ bind() ↓ listen() ↓ accept() ↓ read()/write() ↓ close()
이 순서를 단순 암기하기보다 각 함수의 역할을 연결해서 이해하면 오래 기억됩니다.
socket()은 Kernel에 네트워크 통신용 Socket 구조체 생성을 요청합니다. 성공하면 File Descriptor를 반환합니다.
TCP의 경우 일반적으로 IPv4라면 AF_INET, 연결 지향 Stream 방식이라면 SOCK_STREAM을 사용합니다.
시험 답안형 문장: socket()은 네트워크 통신을 위한 Endpoint를 생성하고 이를 식별하는 File Descriptor를 반환한다.
bind()는 생성한 Socket에 서버의 IP 주소와 Port 번호를 연결합니다.
즉 socket()이 “통신용 객체를 만든다”면 bind()는 “이 객체가 어느 주소와 Port에서 동작할지 정한다”는 의미입니다.
실기 빈칸 문제에서 socket() → ( ? ) → listen() → accept()가 나오면 정답은 bind()입니다.
listen()은 Socket을 Passive Listening State로 전환합니다. 이때 Kernel은 들어오는 연결 요청을 관리하기 위한 대기 Queue를 사용합니다.
중요한 점은 listen()이 실제 Client와 데이터 통신을 시작하는 함수가 아니라, “연결 요청을 받을 수 있도록 준비하는 함수”라는 점입니다.
accept()는 대기 중인 Client의 연결 요청을 수락하고, 실제 데이터 송수신에 사용할 새로운 Socket File Descriptor를 반환합니다.
Listening Socket은 그대로 유지되므로 이후 다른 Client의 연결 요청도 계속 받을 수 있습니다.
이 부분은 실무에서도 중요합니다. 하나의 서버가 여러 Client를 처리할 수 있는 이유가 바로 Listening Socket과 Connected Socket이 분리되어 있기 때문입니다.
Client는 Server처럼 bind/listen/accept 순서를 거치지 않고 보통 다음 흐름으로 이해하면 됩니다.
socket() ↓ connect() ↓ read()/write() ↓ close()
즉 Server는 “기다리는 쪽”, Client는 “연결을 요청하는 쪽”입니다.
TCP는 연결 지향 프로토콜입니다. 실제 데이터를 송수신하기 전에 양쪽이 통신 가능한 상태인지 확인하고 Sequence Number를 동기화합니다.
Client Server
│ │
│ -------- SYN --------------> │
│ │
│ <----- SYN + ACK ----------- │
│ │
│ -------- ACK --------------> │
│ │
Connection Established
핵심은 SYN → SYN+ACK → ACK입니다.
실기 기출에서는 3-Way Handshake 과정에서 받은 Sequence Number에 얼마를 더해 ACK를 보내는지를 묻는 문제가 출제되었습니다.
정답은 1입니다.
SYN 자체가 하나의 Sequence 공간을 소비하므로 상대가 보낸 Sequence Number에 1을 더한 값을 ACK Number로 사용합니다.
시험 암기: TCP 연결 수립 시 ACK = 받은 Sequence Number + 1
TCP 종료에서는 양쪽의 송신 방향을 각각 독립적으로 닫아야 하므로 일반적으로 4-Way Handshake를 사용합니다.
Host A Host B │ │ │ -------- FIN --------------> │ │ <------- ACK -------------- │ │ <------- FIN -------------- │ │ -------- ACK --------------> │
연결 수립은 3-Way, 연결 종료는 4-Way라는 대비는 시험에서 매우 자주 사용됩니다.
listen() 상태의 Server에 Client가 connect()를 시도하면 Kernel 내부에서 TCP 3-Way Handshake가 진행됩니다.
Handshake가 완료되어 연결이 성립되면 accept()가 연결된 Socket을 Application에 반환합니다.
즉 Application Level의 Socket API와 TCP Protocol Level의 Handshake는 서로 다른 계층이지만 실제 동작에서는 긴밀하게 연결되어 있습니다.
UART(Universal Asynchronous Receiver Transmitter)는 대표적인 비동기 직렬 통신 방식입니다.
별도의 Clock Line을 사용하지 않기 때문에 송신기와 수신기는 미리 약속된 Baud Rate를 기준으로 Bit Timing을 맞춥니다.
대표적인 Frame 구조는 다음과 같이 이해할 수 있습니다.
Idle → Start Bit → Data Bits → Parity(optional) → Stop Bit → Idle
UART는 Start Bit와 Stop Bit를 사용하며, TX와 RX Line을 분리하면 Full-Duplex 통신이 가능합니다.
기본적인 UART 통신은 다음 두 신호를 중심으로 이해하면 됩니다.
TX — 송신 데이터
RX — 수신 데이터
필요에 따라 GND를 공통으로 사용하며, Hardware Flow Control을 사용할 경우 RTS/CTS 등이 추가될 수 있습니다.
시험 핵심은 다음 세 문장입니다.
① UART는 비동기 직렬 통신이다.
② 별도의 Clock Line을 사용하지 않는다.
③ Start Bit와 Stop Bit를 사용한다.
SPI(Serial Peripheral Interface)는 Master가 Clock을 공급하는 동기식 직렬 통신 방식입니다.
실기 기출에서는 SPI에 사용되는 네 개의 신호선을 직접 쓰는 문제가 출제되었습니다.
SCLK(또는 CLK) — Clock
MOSI — Master Out Slave In
MISO — Master In Slave Out
CS 또는 SS — Chip Select / Slave Select
이름을 Master 기준으로 읽으면 쉽습니다.
MOSI = Master Out, Slave In
Master가 내보내고 Slave가 받는 선입니다.
MISO = Master In, Slave Out
Slave가 내보내고 Master가 받는 선입니다.
즉 “앞의 두 글자가 Master 기준 방향”이라고 기억하면 됩니다.
한 Master에 여러 Slave를 연결할 수 있기 때문에 현재 어느 Slave와 통신할지 선택해야 합니다. 이때 사용하는 신호가 CS(Chip Select) 또는 SS(Slave Select)입니다.
보통 하나의 Slave를 선택하기 위해 해당 CS Line을 활성화하고, 나머지 Slave는 비활성 상태로 둡니다.
| 항목 | UART | SPI |
|---|---|---|
| 방식 | 비동기 | 동기식 |
| Clock Line | 없음 | SCLK 사용 |
| 대표선 | TX, RX | SCLK, MOSI, MISO, CS |
| 동기 기준 | Baud Rate | Clock |
| 대표 사용 | Console, Modem, Serial Device | ADC, DAC, Sensor, Flash |
Linux User Application에서는 Hardware Register에 바로 접근하기보다 Device Driver와 Device Node를 통해 접근합니다.
대표적으로 UART는 /dev/ttyS*, /dev/ttyUSB*와 termios API를 이용하고, SPI는 /dev/spidevX.Y와 spidev Interface를 사용할 수 있습니다.
즉 앞선 6편과 9편에서 배운 User Space → Device Node → Driver → Hardware 구조가 이번 통신 인터페이스에서도 그대로 적용됩니다.
TCP Server 연결이 안 될 때는 다음 흐름으로 확인할 수 있습니다.
① socket() 생성 성공 여부
② bind()의 IP와 Port가 올바른가
③ Port가 이미 사용 중이지 않은가
④ listen() 상태에 들어갔는가
⑤ Firewall 또는 Network Routing 문제는 없는가
⑥ Client가 올바른 IP/Port로 connect()하는가
⑦ 3-Way Handshake SYN/SYN+ACK/ACK가 실제 발생하는가
⑧ accept()가 정상적으로 Connected Socket을 반환하는가
UART 문제는 양쪽 설정이 일치하는지부터 확인해야 합니다.
① Baud Rate
② Data Bits
③ Parity
④ Stop Bits
⑤ TX/RX Cross 연결 여부
⑥ GND 공통 여부
⑦ Logic Level 일치 여부
⑧ 수신 Overrun/Framing Error 여부
특히 “한 글자는 나오는데 깨진다”면 Baud Rate나 Clock 오차를 먼저 의심하는 것이 좋습니다.
SPI에서는 단순한 배선 외에도 Timing 조건을 확인해야 합니다.
① SCLK가 실제 출력되는가
② CS가 올바른 Slave를 선택하는가
③ MOSI/MISO 방향이 맞는가
④ Clock Polarity와 Phase 설정이 Slave 사양과 맞는가
⑤ Data Bit Order가 일치하는가
⑥ 통신 속도가 Slave 허용 범위 내인가
시험에서는 우선 네 신호선과 동기식 통신이라는 핵심부터 확실히 기억하는 것이 중요합니다.
문제 1. TCP Server Socket의 일반적인 시스템 콜 순서를 쓰시오.
답: socket() → bind() → listen() → accept()
문제 2. TCP 연결 수립 시 사용하는 Handshake는?
답: 3-Way Handshake
문제 3. TCP 연결 종료 시 사용하는 Handshake는?
답: 4-Way Handshake
문제 4. TCP 3-Way Handshake에서 ACK 번호는 받은 Sequence Number에 얼마를 더하는가?
답: 1
문제 5. UART의 특징을 설명하시오.
모범답안: UART는 별도의 Clock Line 없이 미리 설정한 Baud Rate를 기준으로 통신하는 비동기 직렬 통신 방식이다. Start Bit와 Stop Bit를 사용하며 TX와 RX를 분리하면 전이중 통신이 가능하다.
문제 6. SPI의 네 가지 대표 신호선을 쓰시오.
답: SCLK, MOSI, MISO, CS(SS)
TCP Server = socket → bind → listen → accept
TCP Connect = SYN → SYN+ACK → ACK
ACK = 받은 Sequence Number + 1
TCP Close = 4-Way Handshake
UART = 비동기 / Clock 없음 / Baud Rate / Start·Stop Bit / TX·RX
SPI = 동기식 / SCLK / MOSI / MISO / CS
MOSI = Master Out Slave In
MISO = Master In Slave Out
TCP Socket은 함수 호출의 순서, TCP Protocol은 Packet 교환의 순서, UART와 SPI는 신호선의 역할과 Timing이 핵심입니다.
따라서 이번 편은 다음 네 줄로 압축할 수 있습니다.
socket → bind → listen → accept
SYN → SYN+ACK → ACK
UART = Clock 없는 비동기 Serial
SPI = Clock 기반 4선식 Serial
이 네 흐름을 먼저 익히고 세부 내용을 붙이면 실기 서술형과 빈칸 문제 모두 안정적으로 대응할 수 있습니다.
17편 — C Pointer, Struct, Union, malloc/free와 Double Free: 실기에서 자주 나오는 C 언어 핵심
#임베디드기사 #임베디드기사실기 #TCP #SocketProgramming #ThreeWayHandshake #FourWayHandshake #socket #bind #listen #accept #UART #SPI #MOSI #MISO #SCLK #ChipSelect #EmbeddedLinux #SerialCommunication #임베디드시스템 #자격증공부