루프백과 127.0.0.1
인터페이스
인터페이스 = 컴퓨터가 네트워크와 통신하는 “창구”. 보통 물리 NIC 에 대응한다 (eth0, ens33). 꼭 물리적일 필요는 없다.
루프백 (loopback)
루프백 = 물리 하드웨어가 없는 가상 인터페이스. 리눅스 이름 lo, IP 127.0.0.1 (IPv6 ::1).
- 이 인터페이스로 보낸 패킷은 네트워크로 나가지 않고 자기 자신에게 돌아온다. 케이블·스위치·NIC 를 거치지 않고 커널 안에서 U턴.
- 용도 = 같은 컴퓨터의 두 프로그램이 네트워크 방식으로 통신 (예: 웹 서버 →
127.0.0.1:5432DB). - 대역 =
127.0.0.0/8전체(127.0.0.1~127.255.255.255). 관습적으로127.0.0.1만 쓴다.
localhost vs 127.0.0.1
127.0.0.1= 실제 IP 주소.localhost= 그 주소에 붙은 이름./etc/hosts가 둘을 연결한다.
127.0.0.1 localhost
::1 localhostlocalhost는 이름이라 resolve 과정을 거친다 →/etc/hosts수정 시 다른 곳을 가리킬 수도.localhost가 IPv4(127.0.0.1) 와 IPv6(::1) 둘 다에 매핑된다 → 프로그램에 따라 IPv6 로 붙기도 한다.- “
127.0.0.1로는 되는데localhost로는 안 됨” 의 흔한 원인 = IPv4/IPv6 차이.
패킷이 NIC 없이 U턴하는 과정
- 앱이
127.0.0.1로 송신 → 소켓 → 커널 네트워크 스택. - 커널 라우팅 = “목적지
127.0.0.1은lo담당”. - 패킷이
lo의 송신 경로로. lo는 가상이라 내보낼 하드웨어가 없다 → 송신 패킷을 곧바로 자신의 수신 경로로 재투입.lo의 수신 경로 → 커널 스택 → 목적지 소켓의 수신 버퍼.
- U턴 지점 =
lo의 송신·수신을 잇는 커널 네트워크 스택 내부. - 물리 계층(전기신호·케이블·NIC) 은 통째로 건너뛴다.
- 단, TCP/IP 처리(시퀀스 번호·체크섬) 는 그대로 거친다.
층위 비교
- 루프백 = 물리 계층 바이패스.
- DPDK 등 커널 바이패스 = 커널 네트워크 스택 자체 바이패스. 한 단계 더.
바인딩 — 어느 인터페이스에서 받을지
바인딩 = 서버가 listen 할 때 “어느 인터페이스에서 연결을 받을지” 정하는 것.
| 바인딩 주소 | 동작 |
|---|---|
127.0.0.1:8080 | 루프백 전용. 같은 컴퓨터 내 연결만. 외부 접속 불가. |
0.0.0.0:8080 | 모든 인터페이스. 외부 접속 가능. |
전형적 트러블 = “포트가 listen 중인데 외부에서 접속 안 됨” → ss -tulpn 으로 바인딩 주소 확인 → 127.0.0.1:8080 이면 루프백에만 묶인 것 → 0.0.0.0 으로 변경. |
IP 확인
- 인터페이스 IP = 그 인터페이스가 가진 주소. 호스트 자신이 본 모습. NAT 뒤라면 사설 IP.
ip addr/ifconfig로 봄. - 외부 (public) IP = 인터넷에서 본 내 IP. NAT 라우터·VPN 의 출구 IP. 호스트 자신은 직접 모른다 → 외부 서비스에 물어봐야 함.
| 알고 싶은 것 | 도구 |
|---|---|
| 내 인터페이스 IP | ip addr, ifconfig, hostname -I |
| 외부에서 본 내 IP | curl ifconfig.co, curl ifconfig.me, curl ipinfo.io/ip |
ifconfig 출력 해부
root@lima-default:~# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.5.15 netmask 255.255.255.0 broadcast 192.168.5.255
inet6 fe80::5055:55ff:fe3d:a9b1 prefixlen 64 scopeid 0x20<link>
ether 52:55:55:3d:a9:b1 txqueuelen 1000 (Ethernet)
RX packets 21647 bytes 29662336 (29.6 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2818 bytes 215856 (215.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 95 bytes 7812 (7.8 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 95 bytes 7812 (7.8 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0필드별:
eth0= 인터페이스 이름. 관례 =lo루프백,eth*/ens*/enp*이더넷,wlan*WiFi,docker0도커 브리지,br-*브리지,tun*/tap*VPN.flags=4163<UP,BROADCAST,RUNNING,MULTICAST>= 인터페이스 상태 비트마스크.UP= admin 활성화 (ip link set eth0 up으로 켬).RUNNING= 매체(케이블·반송파) 연결됨. UP 인데 RUNNING 아니면 케이블 빠진 상태.BROADCAST/MULTICAST= 해당 트래픽 지원.
mtu 1500= Maximum Transmission Unit. 한 패킷의 최대 바이트(헤더 포함). 이더넷 기본 1500. 루프백(lo) 은 65536 — 가상이라 크게 잡음.inet 192.168.5.15= IPv4 주소.192.168.0.0/16은 RFC 1918 사설 대역 → 인터넷에서 안 보임. (사설 대역 =10/8,172.16/12,192.168/16.)netmask 255.255.255.0= 같은 서브넷 판정 마스크. CIDR/24와 같음.broadcast 192.168.5.255= 그 서브넷의 브로드캐스트 주소.inet6 fe80::5055:55ff:fe3d:a9b1= IPv6 link-local 주소.fe80::/10대역, 같은 링크 안에서만 유효. MAC 에서 자동 생성됨.prefixlen 64= IPv6 prefix 길이 (/64).scopeid 0x20<link>= link-local 스코프.ether 52:55:55:3d:a9:b1= MAC 주소. (52:55:55는 lima/QEMU 가상 NIC 의 가짜 OUI.)txqueuelen 1000= 송신 큐 길이.RX/TX packets/bytes/errors/dropped= 부팅 이후 누적 통계. errors·dropped 가 계속 늘면 NIC·드라이버·케이블 문제 의심.
lo = 루프백 인터페이스. 127.0.0.1 만 가짐. 위 ## 루프백과 127.0.0.1 에서 더.
curl ifconfig.co — 외부 IP 확인 원리
root@lima-default:~# curl ifconfig.co
192.0.2.20동작 = 단순한 HTTP GET. 서버가 받은 TCP 커넥션의 source IP 를 응답 본문에 echo 해주는 서비스다.
- 내 호스트 → (NAT 라우터·게이트웨이) → 인터넷 →
ifconfig.co서버 - 서버가 받는 패킷의 src IP = NAT 의 외부 IP (내 인터페이스 IP 아님)
- 그 IP 를 그대로 본문으로 돌려줌
→ 도구
ifconfig와 도메인ifconfig.co는 이름만 우연히 비슷. 별 관계 없음.
대체 서비스:
curl ifconfig.me
curl icanhazip.com
curl ipinfo.io/ip
curl https://api.ipify.org
# DNS 기반 (HTTP 안 거치는 정통파)
dig +short myip.opendns.com @resolver1.opendns.com최신 도구 = ip (iproute2)
ifconfig 는 net-tools 의 옛 도구로 deprecated. 현대 배포판은 iproute2 의 ip 사용. (왜 갈라졌는지는 아래 ## 네트워크 진단 도구 참고.)
ip addr # = ip a, 모든 인터페이스의 IP
ip addr show eth0 # 특정 인터페이스만
ip -4 addr # IPv4 만
ip -6 addr # IPv6 만
ip -br addr # brief: 한 줄씩 요약
ip link # L2 (MAC, MTU, 상태)
ip route # 라우팅 테이블 — default via ... = 외부 게이트웨이
ip neigh # ARP 테이블
hostname -I # 내 IP 만 공백 구분 한 줄
hostname -i # /etc/hosts 기반 (보통 127.0.1.1, 신뢰 X)스크립트에서 외부 IP 잡기:
IP=$(curl -s ifconfig.co)Lima 실습
lima-default 안에서:
# 같은 인터페이스를 두 도구로
root@lima-default:~# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.5.15 netmask 255.255.255.0 broadcast 192.168.5.255
inet6 fe80::5055:55ff:fe3d:a9b1 prefixlen 64 scopeid 0x20<link>
ether 52:55:55:3d:a9:b1 txqueuelen 1000 (Ethernet)
RX packets 320070 bytes 456515445 (456.5 MB)
...
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
...
root@lima-default:~# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host noprefixroute
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 52:55:55:3d:a9:b1 brd ff:ff:ff:ff:ff:ff
altname enx5255553da9b1
inet 192.168.5.15/24 metric 200 brd 192.168.5.255 scope global dynamic eth0
valid_lft 2367sec preferred_lft 2367sec
inet6 fe80::5055:55ff:fe3d:a9b1/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever- 같은 인터페이스를 두 포맷으로 —
eth0 = 192.168.5.15/24,lo = 127.0.0.1/8. ip addr가 더 풍부 = CIDR(/24), DHCP 리스 잔여 시간(valid_lft 2367sec), qdisc(큐 정책fq_codel), altname.
# Brief / 한 줄
root@lima-default:~# hostname -I
192.168.5.15
root@lima-default:~# ip -br addr
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.168.5.15/24 metric 200 fe80::5055:55ff:fe3d:a9b1/64
# 특정 인터페이스만
root@lima-default:~# ip addr show lo
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host noprefixroute# 외부 IP
root@lima-default:~# curl ifconfig.co
198.51.100.92# 라우팅 — default 게이트웨이 확인
root@lima-default:~# ip route
default via 192.168.5.2 dev eth0 proto dhcp src 192.168.5.15 metric 200
192.168.5.0/24 dev eth0 proto kernel scope link src 192.168.5.15 metric 200
192.168.5.2 dev eth0 proto dhcp scope link src 192.168.5.15 metric 200default via 192.168.5.2 dev eth0= “기본 게이트웨이 =192.168.5.2,eth0로 나감”. 외부 향하는 트래픽은 전부 이 IP 로 보냄.192.168.5.0/24 dev eth0 proto kernel scope link= “같은 서브넷은 직접 도달” — 커널이 인터페이스에 IP 할당하면서 자동 추가.192.168.5.2= Lima vmnet 의 NAT 게이트웨이 (실제로는 맥 호스트가 wrapping).
# (옵션) tcpdump 로 curl 패킷 직접 보기
sudo apt-get install -y tcpdump
sudo tcpdump -n -i eth0 'host ifconfig.co' &
curl -s ifconfig.co
# eth0 송신 패킷의 src IP = VM 의 사설 IP (192.168.5.15)
# 응답 본문엔 NAT 통과 후 외부 IP (198.51.100.92). 두 값이 다른 게 핵심.호스트(맥) 와 비교 — 활성 인터페이스만 추려서:
$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
...
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
ether aa:bb:cc:00:11:22
inet 192.168.0.91 netmask 0xffffff00 broadcast 192.168.0.255
media: autoselect
status: active
...
utun4: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1420
inet 10.5.0.2 --> 10.5.0.2 netmask 0xffff0000
# 그 외 anpi*·en1~6·bridge0·awdl0·llw0·utun0~6·ap1·gif0·stf0 = 대부분 inactive
# 또는 시스템 가상 인터페이스 (애플 NIC 슬롯·AWDL·LLW 등). 신경 쓸 필요 없음.
$ curl ifconfig.co
198.51.100.92lo0 = 127.0.0.1— 맥의 루프백 (이름이lo0, 리눅스의lo와 다름).en0 = 192.168.0.91— 활성 Wi-Fi. 맥의 실제 LAN IP.utun4 = 10.5.0.2— VPN 터널 (사용 중인 VPN 클라이언트가 만든 P2P 가상 NIC).- 맥은
ifconfig가 기본.ip addr쓰려면brew install iproute2mac.
외부 IP 가 둘 다 198.51.100.92 — VPN 풀 터널
VM 과 맥의 사설 IP 는 다르지만 외부 IP 는 같다.
| 위치 | 사설 IP | 외부 IP (VPN ON) |
|---|---|---|
| Lima VM | 192.168.5.15 (eth0) | 198.51.100.92 |
| 맥 호스트 | 192.168.0.91 (en0) | 198.51.100.92 |
처음엔 “두 호스트가 같은 집 공유기 NAT 를 거쳐 같다” 로 보였지만, whois 로 확인하니 다른 답. (아래 출력은 실제 결과를 익명화한 형태)
VPN 켰을 때 — 198.51.100.92
$ whois 198.51.100.92
inetnum: 198.51.100.0 - 198.51.100.255
netname: EXAMPLE-VPN-HOST
descr: Example VPN Hosting Inc.
country: XX
...
route: 198.51.100.0/24
origin: AS65001
Example VPN Hosting류 = VPN·프록시 호스팅 인프라로 알려진 사업자 부류 (NordVPN·ExpressVPN 같은 사업자들의 exit 노드가 이런 ASN 에 몰려 있음).- 등록상 country 와 실제 운영 주체 국가가 다른 경우가 흔함 — VPN 사업자가 여러 지역에 exit POP 을 둔다는 의미.
- 즉 집 공유기 WAN IP 가 아니라 VPN 서버의 출구 IP.
VPN 끈 뒤 — 203.0.113.134
$ curl ifconfig.co
203.0.113.134
$ whois 203.0.113.134
inetnum: 203.0.113.0 - 203.0.113.255
netname: EXAMPLE-ISP-NET
descr: Example Telecom Ltd. Consumer Internet
country: XX
...
route: 203.0.113.0/24
origin: AS65002
descr: Example ISP Ltd.
- 가정용 ISP (사용 중인 통신사) — owner / ASN 이 위와 완전히 다름.
- 이게 실제 집 공유기 WAN IP.
실제 흐름 (VPN ON)
Lima VM (192.168.5.15)
↓ Lima vmnet NAT (gateway 192.168.5.2 — 맥이 wrapping)
맥 (en0 = 192.168.0.91)
↓ Mac VPN 클라이언트가 default route 를 utun4 로 가로챔
utun4 (10.5.0.2)
↓ VPN 서버
인터넷 (198.51.100.92, VPN 사업자 출구)
흐름 (VPN OFF)
Lima VM → Mac → 집 공유기 NAT → 인터넷 (203.0.113.134, ISP WAN)
→ VM 과 맥의 외부 IP 가 둘 다 198.51.100.92 였던 진짜 이유 = Mac 의 VPN 이 full-tunnel (default route 통째로 VPN 으로) 이라 Lima 의 outbound 도 같은 터널을 탐. 두 호스트가 같은 NAT 경계가 아니라 같은 VPN 경계 안에 있는 셈.
교훈
- 외부 IP 가 같다 = 무조건 같은 NAT 경계가 아니라, “같은 마지막 출구” 라는 뜻일 뿐.
- 출구 정체를 알려면 =
whois/curl ipinfo.io/<ip>로 IP 의 owner·country·ASN 까지 확인. - VPN ON/OFF 토글로 비교하면 실제 라우팅 차이를 즉시 확인 가능.
네트워크 진단 도구
“네트워크” 는 여러 층위라 도구마다 담당이 다르다.
| 담당 | net-tools (옛) | iproute2 (현대) |
|---|---|---|
| 소켓·커넥션 | netstat | ss |
| 라우팅 테이블 | netstat -r / route | ip route |
| 인터페이스 통계 | netstat -i | ip -s link |
| 인터페이스 IP | ifconfig | ip addr |
| 라우팅 설정 | route add ... | ip route add ... |
netstat 과 ifconfig 는 라이벌이 아니라 애초에 다른 일을 하는 도구다. |
netstat (network statistics)
root@lima-default:~# netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 127.0.0.54:53 0.0.0.0:* LISTEN 1423/systemd-resolv
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 1423/systemd-resolv
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1/init
tcp 0 0 127.0.0.1:34479 0.0.0.0:* LISTEN 4286/containerd
tcp6 0 0 :::22 :::* LISTEN 1/init- 시스템 네트워크 상태 조회 = 열린 커넥션, listen 포트, 라우팅 등.
- 내 서버, DB 커넥션 등을 확인할 때 즉, 특정 포트가 잘 떠있는지 확인할 때 사용한다.
- 대표 관용구 =
netstat -tulpntTCP /uUDP /llisten 중인 소켓만 /p프로세스·PID /n숫자 표시(DNS 조회 생략)
- 오래된 도구. 요즘 배포판은 기본 미설치인 경우가 많다 (
net-tools패키지).
왜 netstat → ss 인데 netstat -r → ip route 인가
- 옛
netstat= 본업(소켓 보기) +-r(라우팅) +-i(인터페이스 통계) 까지 겸직. - 현대
iproute2= 담당별로 재정리.- 소켓·커넥션 →
ss - 라우팅 →
ip route - 인터페이스·IP →
ip addr,ip link
- 소켓·커넥션 →
- 즉 옛
netstat의 기능이 후속에서 둘로 쪼개진 것.ss -r이 없는 이유 = 라우팅이 애초에ss의 담당이 아니라서.
ss (socket statistics) — 현대 표준
netstat의 후속. 더 빠르고 커널 정보를 더 직접 가져온다.- 매핑은 거의 1:1 =
netstat -tulpn→ss -tulpn,netstat -tan→ss -tan.
netstat -an vs ss -an — 다 보기
-a = all (listen + established + 기타), -n = 숫자 표시 (DNS 안 거침). 옵션 조합이 흔한 관용구라 같이 묶음.
netstat -an = TCP/UDP/RAW + UNIX domain sockets 까지 한 번에. listening + established 다.
root@lima-default:~# netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:40363 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp6 0 0 :::22 :::* LISTEN
udp 0 0 192.168.5.15:68 0.0.0.0:*
raw6 0 0 :::58 :::* 7
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ACC ] STREAM LISTENING 2745 /run/systemd/journal/io.systemd.journal
unix 2 [ ACC ] STREAM LISTENING 12816 /run/containerd/containerd.sock
... (수십~수백 줄의 unix socket)netstat -an= “이 시스템에 무슨 네트워크 활동 있나” 한 번에 스캔하는 용도.- Unix socket 까지 다 같이 나옴 — 단점이자 장점.
- 단,
-p없으니 PID 없음. 필요하면netstat -anp.
ss -an = 같은 의도지만 출력 결이 다름. 더 raw — netlink(nl), packet(p_raw), vsock(v_str), mptcp 같은 잘 안 쓰이는 namespace 도 다 노출.
root@lima-default:~# ss -an
RTNETLINK answers: Invalid argument
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
nl UNCONN 0 0 0:1 *
nl UNCONN 4352 0 4:14409 *
p_raw UNCONN 0 0 [35020]:eth0 *
u_str ESTAB 0 0 * 10126 * 10127
u_str LISTEN 0 4096 /run/systemd/journal/io.systemd.journal 2745 * 0
udp UNCONN 0 0 127.0.0.54:53 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:40363 0.0.0.0:*
tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:*
v_str LISTEN 0 0 *:22 *:*
v_str ESTAB 0 0 3:22 2:492025021
mptcp LISTEN 0 4096 127.0.0.1:40363 0.0.0.0:*Netid컬럼이 도구의 통일성 —tcp,udp,nl(netlink),u_str(unix stream),u_dgr(unix dgram),u_seq(unix seqpacket),v_str(vsock = Lima ↔ host 같은 hypervisor 채널),p_raw(raw packet),mptcp(multipath TCP).Send-Q의4096= listen backlog (accept queue 크기 한도). netstat 출력엔 안 나오는 정보.- 첫 줄
RTNETLINK answers: Invalid argument= netlink 일부 조회 실패. 무해. v_str항목은 Lima 같은 VM 환경에서만 보임 (vsock = VM ↔ host 직접 통신).
언제 뭘 쓰나
- 일상 점검 =
ss -tulpn(TCP/UDP listening + PID).-an보다 노이즈 적음. - 시스템 전체 스캔 =
netstat -an또는ss -an. unix socket 까지 보고 싶을 때. - 디버깅 =
ss -tnp state established같은 조건 필터. ss 가 더 강력.
트러블슈팅 활용
- “특정 포트 연결 안 됨” →
ss -tulpn으로 실제 listen 중인지 + 바인딩 주소 확인. - “커넥션이 많이 쌓임” → 상태별로 카운트.
TIME_WAIT다수 = 커넥션을 짧게 자주 맺고 끊는 패턴.CLOSE_WAIT다수 = 앱이 소켓을 안 닫음 (앱 버그 신호).
- “이 포트 누가 쓰나” →
-p옵션으로 프로세스·PID.
패킷 버퍼 — 커널 vs 유저 공간
커널 쪽 (소켓 버퍼) = OS 가 소켓마다 들고 있는 송수신 버퍼.
- 수신 = 데이터 도착 → 앱이
read()로 가져갈 때까지 커널 수신 버퍼에 적재. - 송신 = 앱이
write()한 데이터 → 실제 전송될 때까지 커널 송신 버퍼에 적재. 확인 도구 ss -tm(-m은 메모리 정보)Recv-Q= 커널 수신 버퍼에 쌓였으나 앱이 아직 안 읽은 데이터. 계속 크면 “앱이 처리를 못 따라감”.Send-Q= 보냈으나 상대가 ACK 안 한 데이터. 크면 네트워크·상대 쪽 문제.
sysctl net.ipv4.tcp_rmem/tcp_wmem= 버퍼 크기 기본값·한계.netstat -s/nstat= 시스템 전체 통계, 버퍼 부족 드롭 카운터 등. 유저 공간 쪽 = 앱이 자기 메모리(힙) 에 들고 있는 버퍼.- OS 가 들여다보는 표준 도구가 없다 → 그냥 그 프로세스의 일반 메모리.
- 확인하려면 = 앱 자체 메트릭·로그, 또는 디버거·프로파일러.
- 프로세스 전체 메모리는
top/ps//proc/<pid>/status로 보지만 “그중 버퍼가 얼마” 는 OS 가 구분 못한다. 핵심 구분 = 커널 버퍼는 OS 관리 →ss·sysctl·netstat -s로 조회 가능. 유저 공간 버퍼는 앱 관리 → OS 도구로는 안 보임.
nslookup — DNS 조회
root@lima-default:~# nslookup google.com
Server: 127.0.0.53
Address: 127.0.0.53#53
Non-authoritative answer:
Name: google.com
Address: 142.250.197.14
root@lima-default:~# cat /etc/hosts
127.0.0.1 localhost- 도메인 → IP.
Server는 응답한 resolver,Non-authoritative answer는 캐시·재귀 응답. - 현대 권장 =
dig(더 풍부한 출력). 예)dig +short google.com.
telnet — 포트 listen 확인
root@lima-default:~# telnet google.com 80
Trying 142.250.197.14...
Connected to google.com.
Escape character is '^]'.
^C
Connection closed by foreign host.- L4 에서 특정 포트가 열려있고 서비스가 listening 중인지 확인. TCP 3-way handshake 를 수행한다.
- ping 과는 다르다. ping 은 L3 에서 호스트가 살아있는지만 확인. ICMP Echo Request/Reply 로 동작하고 포트·TCP/UDP 개념은 포함하지 않는다. ping 응답이 안 오면 네트워크 경로·ICMP 차단·호스트 다운 등을 의심.
- 현대 대체 =
nc -zv host port(netcat). telnet 보다 깔끔.
curl -v — HTTPS 핸드셰이크 보기
root@lima-default:~# curl -v https://google.com
* Host google.com:443 was resolved.
* IPv6: (none)
* IPv4: 142.250.197.14
* Trying 142.250.197.14:443...
* ALPN: curl offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 / X25519MLKEM768 / id-ecPublicKey
* ALPN: server accepted h2
* Server certificate:
* subject: CN=*.google.com
* start date: Dec 3 15:50:09 2025 GMT
* expire date: Feb 25 15:50:08 2026 GMT
* subjectAltName: host "google.com" matched cert's "google.com"
* issuer: C=US; O=Google Trust Services; CN=WE2
* SSL certificate verify ok.
* Certificate level 0: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA256
* Certificate level 1: Public key type EC/prime256v1 (256/128 Bits/secBits), signed using ecdsa-with-SHA384
* Certificate level 2: Public key type EC/secp384r1 (384/192 Bits/secBits), signed using ecdsa-with-SHA384
* Connected to google.com (142.250.197.14) port 443
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://google.com/
* [HTTP/2] [1] [:method: GET]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: google.com]
* [HTTP/2] [1] [:path: /]
* [HTTP/2] [1] [user-agent: curl/8.14.1]
* [HTTP/2] [1] [accept: */*]
> GET / HTTP/2
> Host: google.com
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
< HTTP/2 301
< location: https://www.google.com/
< content-type: text/html; charset=UTF-8
< content-security-policy-report-only: object-src 'none';base-uri 'self';script-src 'nonce-etdn54IcTHyGObO82DqZZQ' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
< date: Mon, 22 Dec 2025 12:27:16 GMT
< expires: Wed, 21 Jan 2026 12:27:16 GMT
< cache-control: public, max-age=2592000
< server: gws
< content-length: 220
< x-xss-protection: 0
< x-frame-options: SAMEORIGIN
< alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
<
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>
* Connection #0 to host google.com left intact*= curl 내부 로그(연결·TLS),>= 보낸 요청 헤더,<= 받은 응답 헤더, 본문은 prefix 없음.- TLS 1.3 핸드셰이크 흐름이 한 화면에 = ClientHello → ServerHello → cert 검증 → key exchange → Finished.
- ALPN 으로 HTTP/2 협상, 인증서 체인 3 단(leaf → 중간 → root).
TCP 송·수신 — 커널 구현 관점
프로토콜 보편 흐름 (Segment·Packet·Frame encapsulation, MSS/MTU, OSI 매핑) 은 04. TCP & UDP > 송·수신 흐름과 encapsulation 참고. 여기는 리눅스 커널이 그 흐름을 어떻게 구현하나 — user/kernel 경계, buffer, syscall, driver, NIC — 에 집중.
user mode ↔ kernel mode 경계
송·수신 모두 데이터가 유저 공간 ↔ 커널 공간 사이를 한 번씩 복사된다. 그 복사가 write()·read() syscall.
+----------------------------------------+
| User mode (애플리케이션 영역) |
| Client Process |
| ↓ data 작성 |
| File I/O Buffer (heap 의 buf 변수) |
+----------------------------------------+
↕ write(fd, buf, len) / read(fd, buf, len) (syscall 경계)
+----------------------------------------+
| Kernel mode |
| Socket (fd → struct sock) |
| ↓ |
| TCP send buffer (= ss 의 Send-Q/Recv-Q) │
| ↓ TCP 가 MSS 단위로 segment 만듦 │
| IP layer (packet 만듦, 라우팅 결정) │
| ↓ |
| Driver (ring buffer + DMA) │
+----------------------------------------+
↕ H/W (DMA, 인터럽트)
+----------------------------------------+
| NIC (PHY + MAC) |
| Frame 만들고 전기 신호로 송출 |
+----------------------------------------+
송신 단계
- Client Process =
buf변수에 데이터 작성 (user space heap). write(socket_fd, buf, len)호출 → syscall 진입 → 커널이buf를 TCP send buffer (커널 메모리) 로 복사.- TCP = send buffer 데이터를 MSS 단위로 segment 화. seq·ack·window 부여.
- IP = segment 에 IP 헤더 부여, 라우팅 테이블 확인해 다음 hop 결정.
- Driver = packet 을 NIC 의 ring buffer 에 넣음 (DMA 로 NIC 메모리에 직접 쓰기).
- NIC = Ethernet 헤더 + FCS 부여, frame 으로 전기 신호 송출.
수신 단계
역순:
- NIC = frame 수신 → 인터럽트 (또는 NAPI polling) 로 커널 깨움.
- Driver = NIC 에서 frame 가져와 Ethernet 헤더 검증·제거.
- IP = packet 의 IP 헤더 검증, 자기 IP 면 위로 전달.
- TCP = segment 헤더 검증, 시퀀스 번호로 순서 정렬, TCP recv buffer 에 저장. ACK 송신.
- Application =
read(socket_fd, buf, len)→ 커널 recv buffer 에서 user buffer 로 복사.
그림 요소의 정확한 계층
| 요소 | 계층 | 메모 |
|---|---|---|
| Client Process | L7 Application | HTTP·SSH·custom app |
| Socket (API) | L4~L7 경계 인터페이스 (학술적 L5) | 프로토콜 아님, “fd 를 통한 transport 접근” |
| TCP | L4 Transport | segment 만듦 |
| IP | L3 Network | packet 만듦, 라우팅 |
| Driver | L2 Data Link (SW) | NIC 의 L2 기능을 OS 가 제어. L3 아님 |
| NIC | L1 + L2 (PHY + MAC) | MAC 부 = frame·체크섬, PHY 부 = 전기 신호 |
왜 user/kernel 경계가 중요한가
- syscall = mode switch 비용 발생. user→kernel 전환 + 데이터 복사 (user buffer → kernel buffer).
- 고성능 환경에선 이 복사가 병목 → zero-copy 기법 (
sendfile(),splice(),MSG_ZEROCOPY플래그). - 더 극단적 = 커널 바이패스 (DPDK, AF_XDP) — NIC 와 user space 가 직접 통신, 커널 네트워크 스택 자체를 안 거침. 위
## 루프백과 127.0.0.1의 “층위 비교” 와 같은 맥락. - TCP send/recv buffer 가 커널 안에 있으므로
Recv-Q·Send-Q가 ss 로 보임 — 위## 네트워크 진단 도구의### 패킷 버퍼 — 커널 vs 유저 공간참고.
rmem_max·tcp_rmem — TCP buffer 튜닝
TCP buffer 의 정의 자체는 04. TCP & UDP > MSS vs TCP buffer vs window 참고. 여기는 그 buffer 의 커널 노브.
두 층의 sysctl
net.core.rmem_max/wmem_max= 모든 종류 소켓 buffer 의 절대 상한 (TCP·UDP·raw 다). application 이setsockopt(SO_RCVBUF, ...)으로 키울 수 있는 최대값.net.ipv4.tcp_rmem/tcp_wmem=[min, default, max]3 값. TCP 의 자동 조정(auto-tuning) 범위. 그 max 가 위rmem_max를 넘을 수 없음.
디폴트
rmem_max≈212992(208 KB)tcp_rmem≈4096 87380 6291456(4KB / 85KB / 6MB)- 일반 환경엔 충분, BDP 큰 환경엔 부족.
BDP (Bandwidth-Delay Product)
- 회선 대역 × RTT = “in-flight 가능한 데이터양”
- 10 Gbps × 10ms ≈ 12 MB. 1 Gbps × 100ms ≈ 12 MB
- buffer 가 BDP 보다 작으면 TCP window 가 거기 막혀 throughput 저하
AWS 컨텍스트
- cross-AZ (수 ms RTT) / cross-region (수십 ms RTT) / S3 download / EBS·EFS 대용량 IO 가 BDP 큰 케이스
rmem_max를 25 MB (26214400) 같이 올려 충분한 BDP 흡수
단점
- 메모리 사용 증가 =
연결 수 × 평균 buffer 크기. 수만 연결 받는 서버에선 RAM 부담.
운영 사례
- EKS Worker AMI 가
net.core.rmem_max = 26214400으로 박은 케이스 = 09. AL2023 EKS Worker AMI Migration > OS 튜닝 (sysctl·limits).
확인
sysctl net.core.rmem_max net.core.wmem_max
sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem
ss -ti # 개별 connection 의 mss·snd_wnd 등