이상학의 개발블로그

[리눅스] 소켓은 파일이다?! Everything is a file 본문

OS/Linux

[리눅스] 소켓은 파일이다?! Everything is a file

학학이 2025. 12. 29. 01:12

더보기
flowchart LR
    subgraph HW["하드웨어 / 서비스"]
        HD["💾 디스크"]
        KB["⌨️ 키보드"]
        DOCKER["🐳 Docker"]
    end

    subgraph FILE["파일"]
        D1["/dev/sda"]
        D2["/dev/input/event0"]
        D3["/var/run/docker.sock"]
    end

    subgraph SYSCALL["시스템 콜"]
        O["open()"] --> R["read()"]
        R --> W["write()"]
        W --> C["close()"]
    end

    subgraph APP["응용프로그램"]
        P["프로세스"]
    end

    HD <--> D1
    KB <--> D2
    DOCKER <--> D3
    
    D1 <--> SYSCALL
    D2 <--> SYSCALL
    D3 <--> SYSCALL
    
    SYSCALL <--> P

유튜브의 네트워크 관련 영상을 보다가 소켓은 파일이라는 것을 알고 있어야 한다는 식의 이야기가 있었는데, 당시에 잘 이해가 가지 않았다.

https://www.youtube.com/watch?v=3jQ2dBpiqPo

리눅스에 대해 다시 공부하다가 이 주제를 다시 만나게 됐고 "소켓은 파일이다"를 스스로 이해시켜보려 한다.


먼저 파일(file)은 정확히 뭘까?

문서 파일, 이미지 파일, 영상 파일 이런식으로 컴퓨터가 정보를 저장하는 구조체라고 생각했다.

찾아보니 일반적인 의미에서 파일은 컴퓨터나 기기에서 정보를 저장하는 기본 단위로, 문서, 사진, 음악, 영상 등 특정 목적을 가진 데이터의 집합체를 논리적으로 구분해 놓은 것을 말한다고 한다.

근데, 이 파일의 개념을 리눅스에선 디렉토리, 하드웨어 장치, 네트워크 소켓까지 모두 파일로 취급한다고 한다.

얼마나 강조하고 싶었으면 Everything is a file이라는 말까지 있을까

리눅스 파일엔 유형이 7가지나 된다.

기호 유형 설명 예시
- 일반 파일 텍스트, 바이너리, 이미지 등 document.txt, program.exe
d 디렉토리 다른 파일들을 담는 폴더 /home, /etc
l 심볼릭 링크 다른 파일을 가리키는 바로가기 python → python3
c 문자 장치 파일 문자 단위로 데이터 전송하는 장치 /dev/tty (터미널)
b 블록 장치 파일 블록 단위로 데이터 전송하는 장치 /dev/sda (하드디스크)
s 소켓 프로세스 간 네트워크 통신 /var/run/docker.sock
p 파이프 (FIFO) 프로세스 간 단방향 데이터 전달 명명된 파이프

 

좀 더 구체적인 예로 설명하면, 다음과 같이 리눅스(OS)의 역할 중 파일 시스템 관리, I/O 장치 관리 등을 편하게 하기 위해 모든 것을 파일로 추상화해서 다룬다고 생각하면 된다.

대상 파일로 생각하면 예시
하드디스크 블록 장치 파일 /dev/sda
키보드 입력 문자 장치 파일 /dev/input/event0
네트워크 통신 소켓 파일 /var/run/docker.sock
프로세스 정보 가상 파일 /proc/1/status
시스템 정보 가상 파일 /sys/class/net/eth0

 

그럼 어떤식으로 추상화할까? 일반 텍스트 파일 readme.txt를 생각해 보자.
이 파일로 할 수 있는 것은 readme.txt의 내용을 확인하고 필요하면 내용을 수정(추가/삭제)하는 작업을 할 수 있다.
이제 이 작업을 아래와 같이 나눠보자.

  1. readme.txt 파일을 연다. open()
  2. readme.txt 내용을 확인한다. read()
  3. "hello"를 추가한다. write()
  4. 저장하고 파일을 닫는다. close()  

open(), read(), write(), close()을 시스템 콜이라고 한다.

시스템 콜, 사용자 프로그램이 운영체제 커널에게 서비스를 요청하는 인터페이스

이제부터 소켓은 왜 파일인지 그리고 왜 이렇게 설계했는지 알아보자

결론부터 말하면 리눅스가 다루게 될 모든 자원을 동일한 인터페이스(방식)로 제어하려는 것이다.

소켓은 통신 인터페이스다.
통신을 그냥 전화를 이용한 통화라고 생각할 때, 소켓은 전화기라고 생각해 보자. (당장 이해가 안된다면 조금만 더 따라와 보자)

  1. 통화를 원하는 사람 A가 전화기를 이용해 상대방 번호를 눌러 통화 요청을 한다. open_call()
  2. 전화가 연결되면 A가 말을 한다. write_call()
  3. 말을 끝내면 통화 상대 B의 대답을 듣는다. read_call()
  4. 용건이 끝나면 통화를 종료한다. close_call()

이 비유가 완벽하진 않지만, 리눅스는 이렇게 모든 인터페이스를 동일한 방식으로 추상화하고 이것들을 모두 파일로 관리하게 설계된 것이다.


주 독자가 개발자라 생각하기 때문에 docker.sock 파일이 어떤 식으로 인터페이스화 돼서 명령을 처리하는지 설명하면 다음과 같다.

더보기

어떤 세상인데, 티스토리는 아직도 mermaid 지원을 안 할까?.. 

flowchart TB
    subgraph Terminal["🖥️ 터미널"]
        A["$ docker ps"]
    end
    
    A -->|"① write: 컨테이너 목록 줘"| B
    
    B["📁 docker.sock<br/>(소켓 파일)"]
    
    B -->|"② read: 요청 확인"| C
    
    subgraph Daemon["🐋 Docker Daemon"]
        C["컨테이너 목록? OK!"]
    end
    
    C -->|"③ write: 결과 응답"| D
    
    D["📁 docker.sock"]
    
    D -->|"④ read: 결과 수신"| E
    
    subgraph Result["📋 결과 출력"]
        E["CONTAINER ID | IMAGE | STATUS<br/>a1b2c3d4e5f6 | nginx | Up 2 hours"]
    end

결국 리눅스(OS)는 관리할 자원을 모두 파일로 보고 동일한 인터페이스로 제어해서 일관성이 있게 자원들을 관리할 수 있는 장점이 생겼다.

이젠 이 글의 제목인 "소켓은 파일이다"를 넘어 "리눅스는 파일이다"라고 말해도 될 것 같다.

 

극단적으로 생각하자. 이 세상(리눅스)엔 파일만 있다.

출처: 흑백요리사 시즌2

 

'OS > Linux' 카테고리의 다른 글

[Linux] 리눅스 소유권 변경 chown 실수  (0) 2020.02.24
Comments