리눅스의 기본 구조
리눅스란?
리눅스는 오픈소스 운영체제로 지금 내가 사용하는 ios같은 운영체제 엔진같은 역할을 말한다.
좀 더 풀어서 말하자면 컴퓨터의 자원 즉, 하드웨어를 총괄하고 그 위에서 사용자가 애플리케이션을 돌릴 수 있도록 관리해주는 소프트웨어이다.
우분투같은 리눅스는 리눅스의 배포판이라고 부른다.(레드햇, CentOS..등등)
커널
사물의 중심이라는 뜻을 지닌 커널은 하나의 프로그램으로 구성되어 컴퓨터의 모든 하드웨어와 소프트웨어를 관리한다.
따라서 리눅스라고 한다면 오직 커널만을 의미한다고 한다..!
커널이 관리하는 하드웨어(디바이스)는 CPU, 메모리, HDD, SSD, DVD-ROM 드라이브, CD-ROM드라이브, 그래픽 어뎁터, 네트워크 어뎁터, 사운드 카드, 시계(하드웨어 클록) 등등..
커널이 모든 하드웨어를 총괄하기 때문에 일반 프로그램이 하드웨어를 조작하기 위해서는 커널에 의뢰를 해야한다.
이럴 때 사용되는 것이 시스템 콜(system call)
이라고 부른다.
시스템을 부른다는 의미의 call을 사용
open, read, write, fork, exec, stat, unlink가 있다.
겉으로 보기에는 일반함수를 사용하는 것과 큰차이가 없다.
n = read(fd, buf, sizeof buf);
man을 통한 정보 조회
프로그래밍을 하다가 특정 함수를 알고 싶다면 man을 통해 조회가 가능하다.
man strlen
입력 시 문자열 길이를 반환하는 함수에 대한 설명을 볼 수 있다.
섹션 | 분류 |
---|---|
1 | 실행 가능한 프로그램이나 셸 명령어 |
2 | 시스템 콜 |
3 | 라이브러리 함수 |
4 | 특별한 파일들(디바이스 파일) |
5 | 파일 포맷 |
6 | 게임 |
7 | 규격 등 |
8 | 시스템 관리용 명렁어 |
섹션으로 구분되어 있기 때문에 해당 섹션만 옵션으로 넣어서 조회도 가능하다.
man 3 printf
printf는 1섹션과 3섹션이 있기 때문에 라이브러리 함수만 보고싶다면 위와 같이 조회해야 한다.
GNU libc같은 경우는 info
를 통해 참고하자
라이브러리(libc)
라이브러리 함수를 라이브러리 함수라고 부르는 이유는 실제 도서관같이 책이 잔뜩 있는 것처럼 리눅스 라이브러리에는 파일이 잔뜩있고 그 안에 함수 코드가 들어가 있다.
printf()
같은 함수의 경우 내부적으로 write()라는 시스템 콜을 사용하지만 strlen()
의 경우에는 어떤 시스템콜도 사용하지 않는다.
API
API(Application Programming Interface)
프로그래밍을 통해 무언가를 사용할 때의 인터페이스를 말한다.(연결의 개념)
gcc 빌드
gcc란, GNU 컴파일러 모음(GNU Compiler Collection, 줄여서 GCC)는 GNU 프로젝트의 일환으로 개발되어 널리 쓰이고 있는 컴파일러이다.
빋드 및 이름 변경
vi main.c
gcc main.c
./a.out
위 처럼 터미널에서 vim에디터로 편집하여 gcc를 통해 빌드 후 실행 가능하다.
gcc -o out main.c
-o
플래글 붙여서 이름을 뒤에 붙은 문자열로 변경가능 각 플래그 인자값은 space로 구분한다.
빌드시 주의사항
- 리눅스에서는 대소문자 구분을 엄격하게 구별한다.
- Segmentation fault는 널 포인터를 참조하거나 배열의 범위를 벗어나 접근하게되면 세크멘테이션 폴트에러로 강제 종료된다.
- printf로 하나씩 찍어서 위치를 확인하거나 디버거를 이용하여 해결한다.
옵션 추가
-Wall
gcc 뒤에 -Wall
옵션을 주게 되면 경고 옵션이 전부 활성화되어 인자의 수나 타입이 잘못된 부분을 경고로 출력헤준다.
이러한 옵션을 붙이는 습관은 매우 좋은 습관이다.
-O
최적화 옵셥으로 실행속도를 가능한 범위내에서 향상시키는 것이다. -O
뒤에 숫자를 붙여서 수준을 정할 수 있는데 3이 가장 큰 값이지만 버그를 초래할 수 있어 대부분 -O2
옵션을 사용한다.
실행 인자
실행 인자라고 함은 echo a b x
라는 명령어른 리눅스 터미널에 입력했을 때 echo
는 명령어이고 a b c
는 실행인자라고 칭한다.
실행인자가 프로그램으로 전달되는 과정은 main함수의 인자를 통해 전달된다.
#include <stdio.h>
int
main(int argc, char *argv[])
{
printf("Hello, World!\n");
return 0;
}
argv의 구조는 인자로 a b c
를 입력했을 때
- argv[0]: ./ hello\0
- gcc -o hello main.c를 통해 빌드한 경우
- 문자열 뒤 마지막을 가리키는 널까지 입력받음(스페이스바로 구분되어 있음)
- argv[1]: a\0
- argv[2]: b\0
- argv[3]: c\0
이를 통해 알 수 있는 점은 실행인자를 입력하지 않아도 실행할 때 입력한 명령어도 같이 들어가기 때문에 언제나 1이상임을 알 수 있다.
" "
큰 따옴표는 쉘기능이라고 부르며 감싼 부분을 하나의 인자로 묶어주는 역할이다.
*
별표는 와일드카드라고 부르며 *.c
처럼 사용하면 현재 디렉토리의 모든 .c로 끝나는 파일을 인식한다.
리눅스 중요 개념
파일
파일이라는 용어는 범용적이라 크게 3가지 정도로 나눠서 생각할 수 있다.
- 넓은 의미의 파일
- 좁은 의미의 파일
- 스트림
넓은 의미의 파일은 ls
명령어로 출력되는 모든 것이 파일이라고 할 수 있다.
- 보통 파일: 가장 일반적인 것으로 데이터가 들어가 있는 파일을 말함.(normal file)
- 사람의 눈으로 봤을 땐 텍스트파일, 영상파일, 이미지로 구분이 가능하지만 커널의 관점에서는 보통 파일로 간주한다.
- 디렉토리: 넓은 의미의 파일을 담아 둘 수 있는 파일이다.
- 심볼릭 링크: 다른 파일을 가리키는 파일을 말함.
- 디바이스 파일: 하드웨어를 파일로 표현한 것
- 명명된 파이프: 프로세스간 통신에 사용되는 FIFO라고도 불린다.
파일에는 데이터 그 자체 외에도 다양한 정보가 존재한다.
이를 메타정보라고 칭함
- 파일의 종류, 권한, 크기, 마지막 수정시간
ls -l
명령어를 통해 조회가 가능하다.
따라서 파일은 어떤 데이터를 보유, 메타 정보, 이름으로 지정가능의 성격을 지닌다.
이러한 파일을 관리하는 것이 파일시스템이다.
파일 시스템은 SSD,HDD같은 물리적 기억 장치에 존재하며 디스크를 파티션단위로 나눠 그 위에 파일시스템을 얹어서 마운트하면 거대한 디렉토리 트리가 생성된다.
프로세스
프로레스란, 실행중인 프로그램을 말하며 프로그램이란 파일 형태로 존재하는 실행 가능한 파일을 말한다.
만약 Hello를 출력하는 a.out파일을 만들어 실행하면 실행 할 때 마다 새로운 a.out프로세스가 만들어진다.
다시 말해 하나의 프로그램이 있으면 새로운 프로세스를 계속 만들 수 있는 것이다.
ps -ef
명령어를 통해 현재 시스템에서 수행 중인 프로세스 목록이 표시된다.
출력 결과를 조회하여 통계를 내봐도 한 프로그램에 두개이상의 프로세스가 존재하는 것을 확인할 수 있다.
따라서 프로그램 이름만으로 프로세스를 특정하거나 구별햘 수 없음을 의미한다, 이럴 땐 프로세스 id
로 프로세스를 특정하여야 한다.
이러한 프로세스 id
가 사용되는 예시로 시그널
을 예로 들 수 있다.
가끔 실행 프로그램이 무한루프를 돌 때 프로그램을 강제 종료하기 위해 ctrl + c
를 눌러 프로세스를 종료한 적이 있을 것이다.
이때 사용되는 것이 시그널
이다. 키 입력 시 해당 프로세스에 인터럽트 시그널을 보내 이를 전달받은 프로세스가 자발적으로 종료한다.
스트림
stream의 뜻은 좁은 흐름을 의미하며 컴퓨터측면으로는 바이트의 흐름 즉, byte stream
을 의미한다.
스트림은 다양하게 활용되는데 만약 프로세스가 파일의 내용을 읽고 싶다면 파일에 연결된 스트림을 만들도록 커널에(시스템 콜을 사용하여)의로하게 된다. 그리고 다시 시스템콜을 사용하여 내용을 읽는다.
앞서 기술한 시스템콜의 read는 스트림에서 바이트 열을 꺼내 읽는 것, write는 바이트 열을 스트림으로 흘려 보내는 것이다.
키보드에 입력한 내용이 HDD,SSD에 저장되는 과정 또한 스트림이 연결되어 사용될 수 있다.
키보드에서 프로세스로 스트림이 연결되고 프로세스에서 SSD로 스트림이 연결되어 바이트 열이 전달된다.
스트림 양끝에 프로세스로 연결되어 있는 구조를 파이프(pipe)
라고 한다.
또한, 네트워크 통신에도 사용된다.
이러한 프로세스간의 데이터를 주고 받는 것을 일반적으로 프로세스 간의 통신(IPC)
이라 한다.
리눅스 사용자
리눅스는 다중 사용자 시스템을 지원하는데 다중 사용자 시스템
이란, 여러명의 사용자가 동시에 사용할 수 있는 시스템이다.
이와 반대로 ios나 안드로이드의 경우 다중 사용자 시스템을 지워하지 않는다.
여러명이 사용하는것은 운영체제의 사용적 측면과 구현에 있어서 높은 복잡도를 가지고 있다. 이는 바로 보완성에 직결되어 더욱 안전한 시스템의 근간이 되었다.
안전한 이유는 시스템의 권환과 그룹으로 다중 사용자로 분리하기 때문에 일반사용자가 쉽게 파일을 삭제하지 못한다.
권한
파일을 특정 사용자만 수정/삭제할 수 있도록 하기 위해 파일에 대한 권환이 적용된다.
따라서 사용자별로 읽기/쓰기/실행 가능한 파일로 구별되는 것!
모든 권한을 가지는 사용자를 슈퍼사용자라고 하며 보통은 root
라는 이름을 가진다.
리눅스는 개별 파일별로 소유자와 소유 그룹이 반드시 존재한다.
아래 세집단에 서로 다른 권한 설정이 가능하다.
- 파일을 소유하는 사용자
- 파일을 소유하는 그룹에 속한 사용자
- 그외 사용자
권한의 종류
- 읽을 수 있는 권한(read, r)
- 쓸 수 있는 권한(write, w)
- 실행(execute, x)
따라서, 세 개의 사용자 그룹에 대하여 세 개의 권한 설정이 가능하기 때문에 총 9개의 설정이 가능하다.
drwxr-xr-x
맨 앞 d를 제외한 9개 문자가 권한을 나타낸다.
d는 디렉토리를 나타냄
자주나오는 권한 패턴
- rw-r–r–: 소유자만 읽고 쓸 수 있고, 그 외의 사용자는 읽을 수만 있다. 일반적으로 자주 적용되는 권환이다.
- rwxr-xr-x: 소유자는 읽고 쓸 수 있고, 그 외의 사용자는 읽고 실행만 할 수 있다. 프로그램이나 디렉터리에 사용되는 패턴이다.
- rw——-: 소유자만 읽고 쓸 수 있다. SSH의 비밀 키, 본인 이외 사용자가 봐서는 안 될 파일에 적용되는 패턴이다.
위의 권한들은 8진수로 표기가 가능하다.
r = 4(100), w = 2(010), x = 1(001), - = (000)
따라서 rwxr-xr-x => 755로 나타낼 수 있다.
디렉토리 권한은 조금 다르게 적용된다. 디렉토리의 실행권한이 없는 경우에는 읽기/쓰기의 권환과 상관없이 접근이 불가능하다.
자격증명
사용자가 파일에 접근할 때 해당 사용자가 권한을 가진 사용자인지 판단을 어떻게 진행이 될까?
사실 사용자가 접근한다는 것은 사용자의 속성을 가진 프로세스가 접근한다는 뜻이다.
이 처럼 프로세스가 가지는 사용자의 속성을 자격증명
이라고 하며, 이 프로세스가 리눅스상에서 이 사용자의 대리인으로 동작한다는 증명서이다.
이러한 자격증명이 부여되는 시기는 초기의 로그인 시기 때 자동으로 생성되며 최초의 프로세스가 다른 프로세스를 실행할 때 증명서를 자동으로 복사하고 전달하므로 로그인 후 생성한 모든 프로세스는 자격증명을 가지게 된다.
모두를 위한 리눅스 프로그래밍책을 기준으로 작성하였습니다.
댓글남기기