사전 Windows
구현체

Windows

gabury1고친 사람 github-actions[bot]

Windows 는 컴퓨터 한 대의 하드웨어를 여러 프로그램이 나눠 쓰게 해 주는 운영체제입니다. Microsoft 가 만들어 팝니다. 개인 PC 와 회사 서버에 설치해서 씁니다. 프로그램은 하드웨어를 직접 만지지 않고 Windows 에 부탁해서 파일을 읽고 화면을 그립니다.

쉽고 빠른 이해

Windows 는 건물 관리사무소 같은 프로그램입니다. 입주한 가게들이 전기와 수도를 직접 끌어다 쓰지 않고 사무소에 신청하듯, 프로그램도 파일 읽기와 네트워크 쓰기를 Windows 에 신청합니다.

이게 없으면 프로그램마다 디스크와 랜카드를 다루는 코드를 따로 짜야 합니다. 한 프로그램이 실수하면 옆 프로그램의 메모리까지 망가뜨립니다.

돌아가는 방식은 이렇습니다.

  1. 프로그램은 Windows 가 내놓은 함수를 부릅니다
  2. 그 함수가 운영체제 한가운데로 요청을 넘깁니다
  3. 운영체제가 장치를 다루는 프로그램(드라이버)에게 일을 시키고 결과를 돌려줍니다

드라이버는 대부분 운영체제 한가운데와 같은 메모리를 함께 쓰며 돕니다. 이런 드라이버 하나가 잘못 돌면 컴퓨터 전체가 멈춥니다.

Microsoft 제품에 묶인 환경이면 서버로 Windows 를 씁니다. 새로 짜는 백엔드 서버는 대개 Linux 에서 돌립니다. Linux 를 전제로 짠 서버 코드는 Windows 에서 파일 경로나 줄바꿈 같은 작은 차이에 자주 걸립니다.

상세

Windows 는 Microsoft 가 만드는 운영체제입니다. 운영체제는 CPU(Central Processing Unit, 중앙 처리 장치)·메모리·디스크 같은 하드웨어를 여러 프로그램에게 나눠 주는 프로그램입니다. 프로그램끼리 서로 망가뜨리지 못하게 막는 일도 합니다.

데스크톱과 서버가 함께 쓰는 NT 커널

지금 PC(Personal Computer, 개인용 컴퓨터)와 서버에 깔리는 Windows 는 전부 NT 커널 위에 서 있습니다. NT 는 New Technology 의 줄임말입니다. 커널은 운영체제의 한가운데에서 메모리와 실행 순서와 장치를 직접 다루는 부분입니다.

데스크톱용 Windows 와 서버용 Windows Server 는 같은 커널을 씁니다. 겉에 얹는 프로그램과 기본 설정, 라이선스가 다릅니다. 개발 PC 에서 겪은 동작이 서버에서도 대체로 같게 나오는 것은 이 때문입니다.

사용자 모드와 커널 모드

CPU 는 코드를 두 가지 권한으로 돌립니다. 권한이 낮은 쪽이 사용자 모드이고 높은 쪽이 커널 모드입니다. 둘을 나눈 까닭은 프로그램 하나의 실수가 컴퓨터 전체로 번지지 않게 하려는 것입니다.

일반 프로그램은 사용자 모드에서 돕니다. Windows 는 프로그램을 띄울 때마다 프로세스를 하나 만듭니다. 프로세스는 실행 중인 프로그램 하나를 운영체제가 관리하는 단위입니다.

프로세스마다 자기만 보는 가상 메모리 주소 공간을 줍니다. 주소 공간은 그 프로세스가 쓸 수 있는 메모리 주소의 범위입니다. 한 프로세스는 다른 프로세스의 주소를 볼 수 없어서, 한 프로그램이 죽어도 다른 프로그램의 메모리는 멀쩡합니다.

커널과 대부분의 드라이버는 커널 모드에서 돕니다. 드라이버는 디스크나 랜카드 같은 특정 장치를 다룰 줄 아는 프로그램입니다. 커널 모드의 코드는 주소 공간 하나를 함께 씁니다. 커널 모드 드라이버 하나가 잘못된 주소에 쓰면 운영체제 전체가 멈추는 것은 이 때문입니다. 흔히 블루스크린이라 부르는 파란 오류 화면이 이때 뜹니다.

요청이 지나가는 계층

프로그램이 파일 하나를 읽으면 요청은 위에서 아래로 몇 계층을 지납니다. 아래 그림은 그 계층을 두 모드로 갈라 세로로 쌓은 것입니다.

flowchart TD
    subgraph U["사용자 모드"]
        A["프로그램"] --> W["Windows API 함수"]
        W --> N["ntdll · 커널로 들어가는 입구"]
    end
    subgraph K["커널 모드"]
        E["커널"] --> D["드라이버"]
    end
    N -->|시스템 콜| E
    D --> H["하드웨어"]

맨 위 프로그램은 Windows API(Application Programming Interface, 응용 프로그래밍 인터페이스) 함수를 부릅니다. 그 함수는 몇 단계를 거쳐 ntdll.dll 이라는 파일 안의 코드에 닿습니다. 거기서 시스템 콜로 커널에게 일을 부탁합니다. 시스템 콜은 사용자 모드의 코드가 커널에게 일을 부탁하는 통로입니다.

부탁을 받으면 CPU 가 커널 모드로 넘어갑니다. 커널은 드라이버에게 일을 맡깁니다.

프로그램이 부르는 창구, Windows API

API 는 프로그램이 부를 수 있게 내놓은 함수 목록입니다. Windows 의 기본 API 를 Win32 API 라고 부릅니다. 이름에 32 가 붙어 있지만 64비트 Windows 에서도 같은 이름을 씁니다.

이 함수들은 DLL(Dynamic Link Library, 동적 링크 라이브러리) 파일에 들어 있습니다. DLL 은 프로그램이 실행될 때 불러와 붙이는 함수 묶음입니다. kernel32.dll 이 파일과 프로세스 함수를, user32.dll 이 창과 입력 함수를 담습니다.

아래는 C 로 파일을 열고 읽고 닫는 최소 형태입니다. Linux 의 open·read·close 와 하는 일이 같습니다. 열기에 실패하면 이유 번호를 돌려주고 거기서 멈춥니다.

C
char buf[100];
DWORD n;
HANDLE h = CreateFileW(L"a.txt",
    GENERIC_READ, 0, NULL,
    OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE)
  return GetLastError(); // 2: 파일 없음
ReadFile(h, buf, 100, &n, 0); // n: 읽은 수
CloseHandle(h);        // 핸들 반납

실패하면 함수가 특별한 값을 돌려줍니다. 실패 이유는 GetLastError 로 따로 묻습니다. 2 는 파일이 없다는 뜻입니다.

셋째 인자 0 은 이 파일을 여는 동안 다른 프로세스가 읽거나 지우지 못하게 막겠다는 뜻입니다. Linux 는 다른 프로그램이 열어 둔 파일도 지울 수 있습니다. Windows 에서는 여는 쪽이 이 인자로 그것을 막습니다. 이 차이는 아래 표에서 다시 나옵니다.

공개되지 않은 시스템 콜 번호

시스템 콜은 CPU 권한을 올려 커널 코드로 뛰어드는 특별한 명령으로 이뤄집니다. Windows 에서 이 통로를 여는 코드는 ntdll.dll 안에 있습니다.

시스템 콜마다 번호가 붙습니다. Microsoft 는 이 번호를 프로그램이 기대도 되는 약속으로 내놓지 않습니다. 번호는 Windows 판이 바뀌면 달라질 수 있습니다.

Windows 프로그램이 믿는 계약은 한 계층 위의 Win32 API 입니다. Linux 가 시스템 콜 번호와 동작 자체를 오래 지키는 것과 반대입니다. 언어 런타임이나 라이브러리도 Windows 에서는 시스템 콜을 직접 쏘지 않고 DLL 함수를 부르는 쪽으로 짭니다.

핸들

위 코드의 HANDLE 이 핸들입니다. 핸들은 커널이 들고 있는 물건을 프로그램이 가리킬 때 쓰는 번호표입니다. 프로그램은 물건의 메모리 주소를 모릅니다. 번호표만 들고 커널에게 부탁합니다.

Linux 의 파일 디스크립터와 닮았습니다. 다만 핸들이 가리키는 물건은 파일만이 아닙니다. 프로세스·스레드·레지스트리 키도 전부 핸들로 가리킵니다. 다 쓴 핸들은 CloseHandle 로 돌려줘야 합니다. 안 돌려주면 커널 쪽 자원이 쌓입니다.

드라이버가 요청을 넘겨받는 방식

운영체제는 드라이버에게 표준 형태로 일을 맡깁니다. 그 덕에 장치마다 다른 세부를 몰라도 됩니다.

Windows 커널의 I/O 관리자는 I/O(Input/Output, 입출력) 요청을 받아 드라이버에게 나눠 주는 부분입니다. 프로그램이 파일을 읽겠다고 하면 그 요청이 여기로 옵니다.

I/O 관리자는 요청 하나를 IRP(I/O Request Packet, 입출력 요청 패킷)라는 꾸러미로 만듭니다. IRP 에는 무엇을 할지(읽기·쓰기 등)와 어디에 결과를 담을지가 들어 있습니다.

드라이버는 한 장치에 하나만 붙지 않습니다. 여럿이 계층을 이뤄 드라이버 스택을 만듭니다. IRP 는 그 스택을 위에서 아래로 차례로 지나갑니다.

flowchart TD
    M["I/O 관리자 · IRP 를 만든다"] --> F["필터 드라이버 · 요청을 보고 거든다"]
    F --> P["펑션 드라이버 · 장치를 부린다"]
    P --> F2["필터 드라이버 · 아래에 끼기도 한다"]
    F2 --> B["버스 드라이버 · 장치가 꽂힌 버스를 다룬다"]
    B --> V["장치"]

펑션 드라이버가 그 장치의 주된 동작을 맡습니다.

필터 드라이버는 펑션 드라이버의 위나 아래에 끼어 요청을 엿보거나 고칩니다. 백신 프로그램이 파일 읽기를 가로채 검사하는 것이 필터 드라이버로 하는 일입니다.

버스는 여러 장치가 꽂혀 CPU 와 데이터를 주고받는 통로입니다. 버스 드라이버는 그 통로를 맡아, 어떤 장치가 꽂혔는지 알아내고 장치까지 요청을 실어 나릅니다.

드라이버를 처음부터 짜기는 어렵습니다. Microsoft 는 WDF(Windows Driver Frameworks, 윈도우 드라이버 프레임워크)라는 뼈대를 내놓습니다. WDF 로는 사용자 모드에서 도는 드라이버도 만들 수 있습니다. 그런 드라이버는 죽어도 운영체제 전체가 버팁니다.

파일 시스템과 레지스트리

파일 시스템은 디스크 위에 파일과 폴더를 어떤 구조로 적을지 정한 방식입니다. Windows 가 기본으로 쓰는 파일 시스템은 NTFS(New Technology File System)입니다.

NTFS 는 파일마다 누가 읽고 쓸 수 있는지를 목록으로 붙여 둡니다. 이 목록을 ACL(Access Control List, 접근 제어 목록)이라 부릅니다.

NTFS 는 저널링도 합니다. 구조를 고치기 전에 무엇을 고칠지 기록부터 남겨, 도중에 전원이 나가도 구조가 안 깨지게 합니다.

설정은 흔히 레지스트리에 둡니다. 레지스트리는 운영체제와 프로그램의 설정을 담는 트리 모양 데이터베이스입니다. Linux 에서 /etc 아래 텍스트 파일로 두는 설정이 Windows 에서는 대개 이 트리의 키와 값으로 들어갑니다.

Linux 와 부딪히는 차이

백엔드 코드는 Linux 에서 도는 것을 전제로 짜는 일이 흔합니다. 같은 코드를 Windows 에서 돌리면 아래 표의 대목에서 걸립니다. 표의 LF(Line Feed)와 CR(Carriage Return)은 줄바꿈을 나타내는 제어 문자입니다.

대목 Linux Windows
경로 구분자 / \ (대부분의 API 는 / 도 받는다)
줄 끝 LF 한 글자 CRLF(Carriage Return Line Feed) 두 글자
파일 이름 대소문자 가린다 기본으로 안 가린다
열린 파일 지우기 된다 연 쪽이 CreateFileW 셋째 인자로 허락 안 하면 막힌다
새 프로세스 만들기 fork 로 프로세스를 메모리째 복제 CreateProcess 로 새로 띄움
기본 셸 bash 류 PowerShell · cmd

Windows 는 줄을 바꿀 때 CR 과 LF 두 글자를 씁니다. Windows 에서 저장한 셸 스크립트를 Linux 컨테이너에서 돌리면 줄 끝의 CR 한 글자 때문에 명령을 못 찾는 일이 생깁니다.

fork 는 지금 프로세스를 메모리째 복제해 자식을 만드는 호출입니다. Windows 에는 이 호출이 없습니다. 자식은 실행 파일을 처음부터 다시 띄웁니다. 파이썬 multiprocessing 이 Windows 에서 자식마다 인터프리터를 새로 띄우는 방식(spawn)을 쓰는 까닭입니다.

Windows 위에서 Linux 를 돌리는 WSL

Linux 용 도구를 Windows 에서 쓰려는 개발자를 위해 WSL(Windows Subsystem for Linux)이 있습니다. 현재 쓰이는 WSL 2 는 가상 머신 안에서 진짜 Linux 커널을 돌립니다.

Windows PC 에서도 Linux 와 같은 시스템 콜 위에서 서버 코드를 돌려 볼 수 있습니다. Windows 용 Docker 도 대개 이 가상 머신 위에서 Linux 컨테이너를 돌립니다. 다만 Windows 쪽 폴더를 Linux 쪽에서 열면 파일 입출력이 느려질 수 있습니다.

서버로 Windows 를 고르는 경우

Windows 를 서버로 쓰는 쪽은 대개 Microsoft 제품에 묶인 환경입니다. .NET Framework 로 짠 옛 애플리케이션, IIS(Internet Information Services) 웹 서버, 회사 계정을 한곳에서 관리하는 Active Directory 가 그런 예입니다.

반대로 새로 짜는 백엔드 서버는 Linux 에서 돌리는 경우가 흔합니다. 컨테이너와 오픈소스 서버 도구가 Linux 를 먼저 겨냥합니다. 서버용 Windows 에는 라이선스 비용도 붙습니다.

관련 항목

Windows 가 속하는 상위 분류

운영체제 · 커널 · Windows NT 커널 · Microsoft

Windows 와 같은 역할을 두고 겨루는 운영체제

Linux · macOS · FreeBSD · 유닉스 · Android

Windows 의 판과 갈래

Windows Server · Windows 11 · Windows 10 · Windows Embedded · Windows 컨테이너

프로그램이 커널에 닿는 통로

Win32 API · API · DLL · ntdll.dll · 시스템 콜 · 사용자 모드 · 커널 모드 · POSIX

Windows 커널이 관리하는 실행 단위와 자원

프로세스 · 스레드 · 가상 메모리 · 핸들 · 스케줄링 · 인터럽트 · 문맥 교환

Windows 드라이버를 이루는 구성 요소

디바이스 드라이버 · I/O 관리자 · IRP · 드라이버 스택 · 펑션 드라이버 · 필터 드라이버 · 버스 드라이버 · WDF · WDM

Windows 가 데이터와 설정을 담는 저장 방식

NTFS · 파일 시스템 · 저널링 · ACL · 레지스트리

Linux 로 옮길 때 걸리는 차이

CRLF · 경로 구분자 · fork · CreateProcess · 대소문자 구분 · 파일 잠금

Windows 에서 Linux 환경을 돌리는 수단

WSL · 가상 머신 · Hyper-V · Docker · 컨테이너

Windows 서버 환경을 이루는 Microsoft 제품

.NET Framework · .NET · IIS · Active Directory · SQL Server · PowerShell

Windows 가 크게 망가질 때 보는 현상

블루스크린 · 커널 패닉 · 메모리 덤프

다른 이름: 윈도우 · 윈도우즈 · windows · Microsoft Windows · MS Windows