Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

Contents

소개

joinc에는 System Programing 관련되어서 꽤 많은 내용들을 다루고 있다. 그러나 이들 문서가 일회성의 기사형식으로 이루어져 있어서 체계적으로 살펴보기 어렵게 되어있다. 이 미니 사이트는 그동안의 시스템 프로그래밍 관련 내용들을 체계적으로 보기쉽게 정리하기 위한 목적으로 만들어졌다.

  1. proc 파일시스템 포함 - 2006.8.18
부담없이 이야기 하는 형식으로 써나가도록 하겠다. 모든 내용은 리눅스(:12)를 기준으로 작성되었다.

프로그래밍의 꽃 시스템 프로그래밍

확실히 시스템:::프로그래밍(:12)은 지겹고 고리타분한 면이 있다. 윈도우 창을 만드는 것처럼 딱히 눈에 보이는 것도 없고, 게임 제작 따라하기처럼 실행되는 결과물도 보이지 않는다. 컴퓨터와 운영체제(:12)의 원리부터 시작해야 하는데, 모든 학문이 그렇듯이 원리는 지겹다. 하지만 원래 지겹운데다가 고리타분해 보이는게 진국인 경우가 많고, 프로그래밍 역시 마찬가지다.

상식적인 얘기가 되겠다. 시스템 프로그래밍은 운영체제의 자원을 이용하고 제어하기 위한 프로그래밍 기술이다. 게임 프로그램, 네트워크 프로그램, 보안 프로그램, 표계산 프로그램 모두 운영체제 위에서 돌아간다. 당연히 운영체제를 효율적으로 제어할 수 있는 기술을 가지고 있어야지만 효율적인 프로그램의 작성이 가능하다. 이 운영체제 자체가 시스템 프로그램이다.

채팅프로그램을 만든다고 가정해 보자. 교과서적인 네트워크:::프로그램(:12)이지만, 한 백명정도만 지원할려고 하면 프로그램 모델을 어떻게 해야할지 고민을 해야 한다. 입출력:::다중화(:12)를 이용할건지, 멀티프로세스(:12) 기반으로 작성할건지, 멀티쓰레드(:12)기반으로 할건지를 결정해야 한다. 수천명에서 수만명까지를 넘어간다고 하면, 시스템을 분산해야 하는 경우도 발생할 것이다. 그냥 하나의 시스템으로 하기로 했다면, 입출력다중화, 멀티프로세스, 멀티쓰레드를 조합한 모델을 생각해야 할것이다. Linux(:12) 환경이라면 리얼타임시그널(:12), epoll(:12)과 같은 것들을 고려할 수도 있을 것이다.

멀티환경이라면 어떤 IPC(:12)를 사용해야 할지, 이를 이용해서 어떻게 데이터 동기화를 시키고 공유해야할지 암튼 머리아픈 시스템 프로그래밍 관련지식이 요구된다. 대게의 경우에는 해당 환경에 맞는 어떠한 적당한 방법을 찾을 것인가의 문제로 귀결이 된다. 이러한 선택은 프로그램 설계와 바로 맞물려 있다. 잘못된 선택은 잘못 설계된 프로그램을 만들게 되고 많은 경우 설계를 다시해야하는 사태에 직면하기도 한다. 제대로된 선택을 위해서는 시스템 프로그래밍에 대한 이해가 필수적임은 말할필요도 없을 것이다.

임베디드 환경도 마찬가지인데, 경험을 얘기해볼까 한다. 한때 - 지금도? - 국비지원 임베디드(:12) 교육이 유행했던 적이 있었다. 6개월 과정을 들으면 누구라도 취업을 할 수 있을 것이다라는 환상을 심어주었드랬다. 50명이 지원을 했다고 하면, 45명은 도중에 떨어진다고 보시면 된다. 제대로 관련기술을 익히는 사람은 5명내외가 된다. 이유는 시스템 프로그래밍에 대한 지식이 없는 상태에서 시작하기 때문이다. 당연한것 아닌가, 시스템을 낮은 수준에서 직접다루어야 하는 임베디드 환경인데, 시스템 프로그래밍 기술을 모른다면 수업을 따라가는 것 자체가 어려워진다. 끝까지 가는 5명은 애시당초 시스템/네트워크 프로그래밍에 대한 지식을 가지고 있는 사람들이다.

공부하는 프로세스 같은게 딱히 정해져있는건 아니겠지만, 일반적으로는 시스템 프로그래밍 -> 네트워크 프로그래밍 -> 시스템 프로그래밍 -> 응용 식이라고 볼 수 있을 것이다. 시스템 프로그래밍으로 기초를 다지고 그 위에서 네트워크 프로그래밍 기술을 익힌 다음, 다시 시스템 프로그래밍을 깊이 익히고, 이를 바탕으로 자신이 하고픈 분야의 응용 프로그램을 작성하는 식이다.

프로그램을 만들기로 하고 C(:12)가 되었건, C++이나 Java(:12)가 되었건간에 문법을 떼었다면, 시스템 프로그래밍 쪽을 공부해보기 바란다. 건너뛸 수 있는 것도 아니지만, 찬찬히 공부해보면 나름대로 상당히 재미를 느낄 수 있는 분야이기도 하다. Linux(:12)에서 시작하면 더 재미있을 것이다.

개발 환경

이 사이트의 내용들을 익히기 위해서 준비되어야 할 것들이 있다. gnu c, c++ 컴파일러, 코딩을 위한 emacs및 vi와 같은 에디터, 소스코드 관리를 위한 make도구, 협업을 통한 프로젝트의 진행을 위한 cvs, 개발 문서작성을 위한 docbook, latex, gdb와 같은 디버거등이다. man page 역시 빠지면 안될 중요한 개발도구중 하나다.

make와 관련된 몇 가지 문서들이 더있다 참고 하기 바란다.
  1. 간단한 make파일 만들기
  2. tmake를 이용한 Makefile 생성
  • 이 문서를 읽는 분들중 gcc의 사용법을 모르는 분들도 있을 것 같아서 간단한 컴파일 방법을 적어봅니다. hello.c 를 컴파일하려면 다음과 같이 하면 됩니다.
    # gcc -o hello hello.c
이렇게 하면 hello라는 실행파일이 만들어집니다. gcc는 그자체로 책한권 분량이겠지만. 어쨋든 위와 같은 방법으로 최소한의 컴파일은 가능합니다. 참고하시기를. gcc에 대한 좀더 자세한 내용은 C위키를 참고하기 바란다.

eclipse를 이용한 통합 개발환경 만들기

vi(:12)를 처음 접한다면, 사용하기에 다소 번거로울 수가 있을 것이다. 이경우 eclipse(:12)를 이용하면, 통합 IDE환경을 구축할 수 있다. CDT를 이용한 eclipse qt 개발환경 구축CDT를 이용한 eclipse C/C++ 개발환경 만들기를 참고하기 바란다.

유닉스 환경 및 프로세스

우리가 회사에서 어떤 업무를 한다고 했을 때 가장 먼저 하는일은 회사의 업무 환경을 살피는 것이다. 회사가 어떤일을 하는지, 주요고객은 어떠한지, 나는 어느 팀에 소속되어 있고, 팀장은 누구고 동료는 누군지(회사에서의 관계설정), 회사의 이메일주소, 개인 이메일주소, 각종 서류양식은 어디에 있는지... 등등등 회사환경에 대한 이해를 가지고 있어야 원할하게 업무를 진행할 수 있게된다. 업무 수행속도도 빨라지고 문제가 생겼을 때 원인을 쉽게파악하고 문제점을 해결할 수 있기 때문이다.

환경 변수 와 프로그램 실행인자

프로그램역시 그 업무를 제대로 수행하려면 프로그램이 작동하는 여러환경에 대해서 그내용을 가지고 있어야 한다. 흔히 이것을 환경변수 라고 하며, 여러가지 정보들 - 홈디렉토리, UID, 라이브러리 경로, 실행파일 찾기 경로, 언어, 타임존, 터미널... -을 가진다.

환경변수외에도 프로그램의 실행에 영향을 끼치는 것으로 프로그램 인자가 있다. 프로그램 인자는 실행되는 프로그램에 특정 값을 넘기기 위한 목적으로 사용된다.

프로세스 개념

이쯤 해서 프로세스라는 단어가 나온다. 프로세스와 프로그램에 대해서 혼동하지 말도록 하자. 회사원업무수행이 전혀다른 것과 마찬가지다. 프로그램은 어떤 일을 수행하는 주체(이를테면 회사원)고 프로그램이 일을 수행하기 위해서 만들어진 이미지를 프로세스(업무수행)라고 한다.

우리가 수행하는 업무는 단독으로 수행되는 경우도 있지만 다른 업무의 보조 업무로 수행되는 경우도 있고, 혹은 기존 업무를 완전히 대체해 버리는 경우도 있다. 프로세스도 업무수행과 마찬가지로 이러한 관계를 맺으면서 상호작동한다. 리눅스 커널위에서 작동하는 모든 프로세스는 커널에서 작동하므로 프로세스사이의 관계도 중요하지만 커널과 프로세스와의 관계에 대해서 이해하는 것도 중요하다. 이러한 관계들에 대해서 이해하고 있으면 깊이 있는 프로그램의 작성에도 도움이 되고, 문제가 생겼을 때 문제의 원인을 효과적으로 찾아낼 수 있다. 참고로 현재 리눅스 커널은 2.6 버젼까지 개발된 상태다.

프로그램은 실행시 인자를 주어서 프로세스의 작업의 형태를 변경할 수도 있다.

제목 저자 변경일

유닉스 시간

시간은 동기를 위한 목적으로 사용한다. 모임시간의 약속, 일의 시작및 종료시간의 결정..등 모든 약속에는 시간이 들어간다. 컴퓨터의 기본용도가 인간이 할 수 있는 업무를 가능한 정확하게 수행하기 위해 만든 기계라고 봤을적에 시간이라는게 매우 중요할 것이라는건 당연하다. 프로그램의 시작,종료, 중단시간 지정, cron과 같은 배치작업, 프로세스간 동기화 등은 물론이고 멀리 떨어져있는 서버들간에도 정확한 업무 수행을 보장받기 위해서 서로 시간을 동기화 시킨다. 유닉스 환경에서는 특별히 유닉스 시간을 사용해서 시간을 결정한다.

사용자 계정

리눅스는 다른 유닉스들과 마찬가지로 다중사용자 운영체제 이다. 동시에 여러유저가 접근해서 자원을 사용할 수 있으므로 유저에 따른 권한과 활동영역등이 명확히 정의될 수 있어야 한다.

동시에 여러유저에 대한 접근제어를 위해서 리눅스는 다른 유닉스와 마찬가지로 아이디:패스워드의 인증방식을 사용한다. 패스워드에 대한 암호화에는crypt를 사용한다.

이외에도 접근한 사용자에 대한 이력관리를 위해서 utmp도 지원한다.

파일 제어

리눅스는 모든 것을 파일로 다룬다. 일반 파일은 물론이고, 소켓, 파이프, 장치.. 모든게 파일이다. 당연히 파일을 다루는기술은 매우 중요하며, 실제 유닉스 프로그래밍의 가장 주요한 부분이라고 할 수 있다. 리눅스 자체가 다중 사용자 운영체제 이다 보니.. 파일의 읽기/쓰기와 같은 단순한 제어 외에도 파일 권한에 대한 이해와 제어 역시 매우 중요하다.

입출력 다중화

파일을 다루다 보면 동시에 여러개의 입출력을 다루어야 하는 경우가 발생할 수 있다. 이러한 입출력 다중화를 대비해서 유닉스는 selectpoll을 제공한다. 입출력 다중화는 특히 동시에 여러개의 클라이언트를 다루어야 하는 인터네트 서버 프로그램의 작성을 위해 유용하게 사용된다.

파일 특성확인 및 잠금

파일은 운영체제를 이루기 위한 기본단위가 되며, 모든 작업은 파일에서 시작해서 파일로 끝나게 된다. 때문에 파일의 특성 (실행파일인지, 권한은 어떻게 되는지 등)을 아는게 매우 중요하다. 또한 유닉스는 다중 사용자를 지원하기 때문에 하나의 파일에 동시에 두명이상의 유저가 접근하는 경우도 생각할 수 있다. 이경우 한명의 유저가 파일에 접근 할 경우 파일 단위로 잠그거나 파일의 일부를 잠그는 등의 제어가 필요하다.

제목 저자 변경일

IPC

Inter Process Communication 의 줄임말이다. 줄임말에서 알 수 있듯이 내부 프로세스간 통신을 위해사 사용된다. 부서의 직원간의 통신을 위한 각종 도구(전화, 메신저, 구두)와 동일하다고 볼 수 있다.

리눅스는 POSIX와, System V에서 제안한 대부분의 IPC도구들을 지원한다. 여기에는 POSIX IPC인 PIPE, FIFO 과 System V IPC인 공유메모리, 세마포어, 메시지큐등이 있다.

이들 외에도 socket라이브러리에서 제공하는 socketpair, Unix Domain Socket (TCP), UNIX Domain Socket (UDP), socketpair(2), sendfile(2)등이 있다.

제목 저자 변경일

프로세스와 쓰레드

프로세스 생성

프로세스는 앞에서 설명했듯이 특정 작업을 수행하는 (프로그램의) 이미지이다. 프로세스를 생성시키는 유일한 방법은 fork(2)시스템 함수를 이용하는 것이다. 프로세스 관계문서를 읽어 보기 바란다. fork(2)는 특히 다중의 클라이언트를 받아들여야 하는 네트워크 서버 프로그램의 작성에 주요하게 사용된다.

프로세스 실행

프로세스의 실행은 execl()계열의 함수를 이용한다. 이 함수를 이용하면 프로세스를 실행하게 되는데, fork()를 통한 프로세스 생성과 혼동하지 않도록 한다. execl()계열 함수를 이용해서 프로세스를 실행하면 현재 프로세스의 이미지를 완전히 덮어 쓰게 된다. 이에 대한 자세한 내용은 프로세스 관계에 대해서 이해하고 있어야 한다.

execl()과 비슷한 system()함수가 있는데, 이것은 fork()와 execl()의 응용이므로 언급하지 않도록 하겠다.

쓰레드

쓰레드는 LWP라고 불리우며 병렬적으로 수행되는 코드의 조각이다. fork를 통한 다중 프로세스 모델에서는 프로세스간 통신을 위해서 IPC를 사용하는데 쓰레드의 경우는 쓰레드 라이브러리에서 제공하는 뮤텍스, 조건변수등을 이용한다. 쓰레드 취소와 관련된 내용은 쓰레드 취소 문서를 참고하기 바란다.

시그널

회사에서 일을 하다보면 전화, 생리적 현상등으로 인해서 인터럽트(중단)이 걸리게 된다. 이러한 인터럽트는 컴퓨터에서 작동하는 프로세스에도 동일하게 적용된다. 이러한 인터럽트를 알리기 위한 도구로 유닉스에서는 signal을 사용한다. 유닉스에서 사용하는 시그널은 대기열을 가지지 않는다는 특징을 가지고 있다. 어쨋든 우리는 시그널을 통해서 프로세스에 특정한 중단을 만들 수 있다.

시그널이 대기열을 가지지 않는다는 것은 동시에 많은 인터럽트를 처리해야 할경우 문제가 될 수 있는데 이러한 문제의 해결을 위해서 최근의 리눅스는 리얼 타임 시그널을 제공한다. 이것을 이용하면 시그널을 좀더 효율적으로 제어할 수 있다. 리얼 타임 시그널이 기존 시그널에 비해 향상되긴 했지만 signal buffer overflow가 발생할 수 있는 단점역시 가지고 있다. 하지만 대부분의 경우 문제가 되지 않으며, 문제가 될것 같다면 해결책 역시 있으니 크게 걱정할 필요는 없을 것 같다.

제목 저자 변경일

터미널

터미널 (terminal) 은 모니터(moniter)와 키보드(keyboard)의 조합으로 지역적으로 붙어있거나 혹은 원격으로 연결된 컴퓨터와 대화하기 위해서 사용되며, 장치의 개념으로 이해할수 있다. 프로그래머는 프로그램을 실행시키기 위해서 키보드를 이용해서 명령을 실행시키며, 그 결과는 모니터를 통해서 출력된다. 우리는 터미널이 없이는 컴퓨터를 효과적으로 다룰수 없을것이다.

proc 파일 시스템

제목 저자 변경일

문서 디렉토리

제목 저자 변경일

고급응용

Linux 함수 레퍼런스

시스템 함수

제목 저자 변경일

표준 함수

제목 저자 변경일

리눅스 시스템 콜 레퍼런스

Linux System Call 레퍼런스