리눅스 시스템 프로그래밍 - 리눅스 프로그래밍의 개념

김신·2022년 12월 26일
1
post-thumbnail

0. 리눅스 프로그래밍의 개념

리눅스의 기본적이고 핵심적인 추상화 개념은 파일입니다. 리눅스는 모든 것이 파일이라는 철학을 따르며, 모든 상호작용은 실제로 파일을 읽고 파일에 쓰는 것으로 이루어집니다. 리눅스 프로그래밍은 파일을 쓰고 읽는 것이라는 말로 표현할 수 있습니다. 마우스, 키보드, 물리적 저장 공간 등을 다루는 것 모두 리눅스에서는 파일의 입출력으로 이루어집니다.

리눅스와 유닉스 시스템은 추상화와 인터페이스를 제공합니다. 그리고 이런 공통성이 곧 유닉스를 의미합니다. (리눅스와 유닉스가 같냐는 논쟁거리가 됩니다. ) 파일, 프로세스, 파이프 그리고 소켓을 다루기 위한 인터페이스 등의 것들이 유닉스의 핵심이자 리눅스의 핵심이기도 합니다. _

1. 일반 파일

위 그림은 우리가 흔히 파일이라고 부르는 것이고 이는 일반 파일을 의미합니다. 그리고 일반 파일은 바이트 스트림이라고 부르는 연속적으로 나열된 바이트 배열에 저장된 데이터를 말합니다.

파일은 바이트를 읽고 쓰는 것이 가능합니다. 바이트 배열에 읽고 쓰는 행위는 파일 오프셋(file offset)을 사용함으로 좀 더 디테일하게 이루어집니다. 파일 오프셋은 커널이 열린 파일마다 유지하는 메타데이터의 핵심입니다. 파일이 처음 열리면 파일의 오프셋은 0입니다. 그리고 파일에 바이트가 쓰이거나 읽히면 그 바이트만큼 오프셋이 이동합니다. 당연하게 그 단위는 바이트입니다. fseek()함수를 이용하면 offset의 위치를 임의로 지정할 수 있습니다.

파일은 열릴 때마다 파일 디스크립터(file descriptor)를 반환합니다. 시스템 프로그래머는 파일 디스크립터를 이용해 파일을 읽고 씁니다. 프로세스에서는 파일 디스크립터를 공유하며 여러 프로세스에서 파일 디스크립터를 사용해 하나의 열린 파일에 접근할 수 있습니다.

일반적으로 파일 이름을 통해 파일에 접근하지만 실제로 파일은 파일 이름과 직접적으로 연관되어 있지는 않습니다. 파일은 i-node라고 하는 파일시스템 내에서만 고유한 정수 값으로 참조됩니다. 이 값은 i-node 번호라고 하며 i-no라고 줄여서 씁니다. i-node에는 소유자, 타입, 길이, 데이터 저장 위치 같은 메타데이터를 저장하고 있지만, 파일 이름은 저장하지 않습니다. i-node는 유닉스 파일시스템에서 디스크에 저장된 물리적인 객체임과 동시에 리눅스 커널에서 자료구조로 표현되는 논리적인 개념이기도 합니다.

2. 디렉터리와 링크

디렉터리 또한 파일입니다. 개념적으로 일반 파일과 유사한 모습이지만 이름과 i-node의 맵핑만 저장한다는 점에서 차이가 있습니다. 커널은 이런 맵핑을 통해 이름으로 i-node를 찾는 작업을 수행합니다. 디렉터리는 파일에 접근하기 위한 이름을 제공합니다. 이 때 디렉터리는 i-node 대신 파일 이름으로 나타냅니다. 그리고 i-node와 이름의 쌍을 링크라고 합니다.

사용자 영역에서 파일 시스템을 이용해 파일 여려고 요청하면 커널은 파일 이름이 포함된 디렉터리를 열고 파일을 찾습니다. 커널은 파일 이름으로 i-node 번호를 얻고, 이렇게 얻은 i-node 번호로 i-node를 찾습니다. i-node에는 디스크에서 파일의 위치 같은 관련 메타데이터가 있습니다.

디렉터리는 일반 파일과 유합니다. 그리고 디렉터리 또한 파일임으로 i-node가 있습니다. 따라서 디렉터리 내부의 링크 역시 다른 디렉터리의 i-node를 가리킬 수 있습니다. 이렇게 디렉터리는 다른 디렉터리 내부에 존재할 수 있고 계층적인 구조를 형성할 수 있게 됩니다. 이를 활용하면 /user/workspace/dog.png 처럼 컴퓨터를 이용하는 대부분의 사람에게 친숙한 파일 경로를 사용할 수 있습니다.

디스크에서 파일 시스템의 경로는 /로 시작합니다. 이를 루트 디렉터리라고 합니다. 그리고 루트 디렉터리에서 시작하는 경로 이름은 모든 경로를 빠짐없이 나타냅니다. 이를 절대 경로라고 칭합니다. 이에 반해 상대 경로는 현재 작업 디렉터리를 기준으로 사용합니다.

  • 현재 경로가 /user/workspace 라면 dog.png를 찾기 위해서 사용할 수 있는 경로의 예제는 다음과 같습니다.
  • 절대 경로 /user/workspace/dog.png
  • 상대 경로 workspace/dog.png

디렉터리는 일반 파일과 유사하지만, 커널은 사용자 영역에서 디렉터리를 일반 파일처럼 열고 조작하지 못하도록 제한합니다. 디렉터리를 조작하려면 시스템 콜을 사용해야합니다. 이를 위한 시스템 콜에는 링크 추가와 삭제가 있습니다.

3. 하드 링크

하드 링크는 복잡한 파일시스템 구조에서 동일한 데이터를 여러 경로 이름이 가리킬 수 있게 허용합니다. 하드 링크는 동일한 디렉터리에 존재하거나 둘 이상의 다른 디렉터리에 걸쳐 있을 수 있습니다. 특정한 i-node를 /user/workspace/dog.png와 /user/lib/dog.png로 하드 링크를 걸 수 있습니다. 이는 다른 i-ndoe에도 가능한 일입니다.

파일 삭제는 디렉터리 이름과 i-node의 쌍을 삭제하는 것입니다. 리눅스에서는 하드 링크를 지원하므로 단순히 링크를 해제할 때 i-node와 관련 정보를 삭제할 수 없습니다. 왜냐하면 i-node에 다른 하드 링크가 걸려있을 수 있기 때문입니다. i-node의 잘못된 삭제를 방지하기 위해 i-node는 파일시스템 내부에 링크 카운터를 두어 그 문제를 해결합니다. 링크가 삭제될 때마다 카운터를 감소시켜 그 카운터가 0이 된다면 그 때 i-node와 관련된 정보를 실제로 삭제합니다.

4. 심벌 링크

유닉스 시스템은 여러 파일 시스템에서 사용할 수 있는 심벌 링크를 제공합니다.

심벌 링크는 일반 파일과 비슷합니다. 심벌 링크는 링크로 연결할 파일의 절대 경로 이름을 포함하는 독자적인 i-ndoe와 데이터가 담겨 있습니다. 이는 심벌 링크가 다른 파일시스템에 들어 있는 파일과 디렉터리는 물론이고 심지어는 존재하지 않는 파일과 디렉터리를 가리킬 수도 있음을 의미합니다. 존재하지 않는 파일을 가리키는 심벌 링크를 깨진 링크라고 합니다.

5. 특수 파일

특수 파일은 파일로 표현되는 커널 객체입니다. 커널 객체란, 이벤트 객체, Mutex, 프로세스, 스레드 등과 같이, 오직 커널만 접근 할 수 있는 객체들을 말한다. 리눅스는 네 종류의 특수 파일을 지원합니다. 네 종류는 블록 디바이스 파일, 캐릭터 디바이스 파일, 네임드 파이프, 유닉스 도메인 소켓입니다.

유닉스 시스템에서는 하드웨어 장치에 대한 접근 또한 파일을 거쳐 실행됩니다. 이런 파일이 파일시스템에 있는 디바이스 파일입니다. 디바이스 파일은 일반 파일처럼 생기고 실제 일반 파일처럼 동작합니다. 유닉스와 리눅스에서 파일을 열고, 읽고, 쓰는 방식으로 사용자 영역에서 하드웨어 장치로의 접근을 허용하며 시스템에 있는 하드웨어 장치를 조작합니다. 유닉스에서 하드웨어 장치는 캐릭터 디바이스와 블록 디바이스로 나뉩니다.

캐릭터 디바이스는 바이트로 구성된 선형 큐처럼 접근할 수 있습니다. 디바이스 드라이버는 큐에 바이트를 하나씩 집어 넣고, 사용자 영역에서는 큐에 쌓인 순서대로 바이트를 읽어냅니다. 캐릭터 디바이스의 대표적인 예는 마우스와 키보드입니다. 입력한 순서대로 데이터가 읽어집니다. 키보드에 'korea'라고 차례대로 입력하면 소프트웨어는 키보드 디바이스에서 k, o, r, e, a를 순서대로 읽어냅니다.

블록 디바이스는 바이트 배열로 하드웨어에 접근합니다. 디바이스 드라이버는 위치 지정이 가능한 장치에 여러 바이트를 맵핑해 사용자 영역에서 이 배열이 포함되고 있는 유효한 바이트에 임의로 접근할 수 있습니다. 블록 디바이스의 대표적인 예는 하드 디스크, 플로피 드라이브 등 입니다.

네임드 파이프는 IPC 메커니즘입니다. 그리고 특수 파일을 읽고 쓰는 파일 디스크립터를 사용하는 통신 채널을 제공합니다. 일반 파이프는 통신을 위해 (데이터를 주고 받기 위해) 프로세스와 프로세스를 잇는 방법입니다. 일반 파이는 시스템 콜로 만들어지며 메모리 위에 존재합니다. 그러나 네임드 파이프는 일반 파이프와 동일하게 동작하지만 FIFO라는 특수한 파일을 거쳐 접근합니다. 서로 무관한 프로세스도 이 파일에 접근하는 방식으로 서로 통신이 가능합니다. (일반 파이프는 관련 있는 프로세스 사이의 통신을 지원합니다. ex: parent - child process)

소켓은 서로 다른 프로세스끼리 통신을 할 수 있는 고급 IPC의 한 종류입니다. 같은 머신 안의 통신 뿐만 아니라 다른 머신 끼리도 통신이 가능하도록 합니다. 소켓은 네트워크와 인터넷 프로그래밍의 근간을 이루고 있습니다. 로컬 머신 내부에서 통신을 위해 사용하는 소켓 형태인 유닉스 도메인 소캣을 포함하여 소켓에는 많은 변종이 있습니다. 인터넷에서 통신하는 소캣은 통신 목적지를 파악하기 위해 호스트 이름과 포트를 사용하지만, 유닉스 도메인 소켓은 파일시스템에 만들어진 특수파일인 소켓 파일을 사용합니다.

0개의 댓글