풀악셀을 밟으면서 CS 기초를 쌓고자(?) 인강을 때려넣는 중이다. 방대한 영역을 짧은 시간 안에 듣다보니 세세하게 듣고 기억하기는 어렵고 일단 큰그림을 대충 파악하는 걸 목표로 하려고 한다. 그리고 이렇게 한번쯤 들어봤으니 나중에 다시 찾아볼 수 있기를 바라며.. (미래의 나 화이팅..!)
시스템 프로그래밍
시스템의 여러 자원을 활용해서 프로그래밍을 하는 것. 시스템 호출 함수랑 라이브러리 함수를 이용해서 작성한다. 시스템 프로그래밍을 하게 되는 상황이 바로 서버를 운영하는 것인데, 서버는 대부분 리눅스 운영체제에서 돌아가기 때문에 시스템 프로그래밍도 리눅스 운영체제를 중심으로 배우게 됐다.
강의에서는 크게 파일 다루기, 프로세스와 스레드 다루기, 소켓 프로그래밍을 했다. 시스템의 기본은 디렉터리와 파일을 다루는 것! 그리고 시스템이 어떻게 프로세스를 알아보고, 만들고, 관리할 수 있는지를 배우고, 프로세스끼리 정보는 어떻게 주고받는지 알아본다. 그리고 소켓 프로그래밍은 네트워크를 활용해서 간단하게 통신할 수 있는 방법인 듯 하다. 리눅스 시스템은 C언어 만들어졌다. 그래서 실습파일도 모두 C언어를(씨알못...) 가지고 '관찰'을 했는데, 각 호출 함수에 따라 들어가는 인자들이 비슷비슷하긴 하지만 조금씩 달랐다.
시스템 호출 : 리눅스에서 프로그래밍 인터페이스를 통해 파일에 접근하거나 각종 정보(사용자 정보, 시스템 정보) 등을 활용할 수 있게 하는 것이 '시스템 호출'이다. "시스템아 이 파일 좀 열어줘." 이런 요청이 시스템 호출... 시스템 프로그래밍을 배우는 사람 입장에서는 내가 시스템한테 호출하는 것처럼 보이지만, 결과적으로는 시스템 프로그래밍으로 만든 프로그램이 운영체제한테 작업을 요청하는 것이다.
시스템 호출의 기본 형식은 이렇게 생겼고, 호출을 하면 보통 성공했다거나 실패를 알려주는 정수값을 리턴한다. 성공은 0 실패는 -1.
리턴값 = 시스템 호출명(인자1, 인자2, ...)
1. 디렉터리 다루기
리눅스에서는 디렉터리(폴더)를 마치 파일처럼 취급한다. 리눅스에서 파일은 파일명, 아이노드(inode), 데이터 블록으로 구성된다. 아이노드는 파일에 대한 정보를 저장하고 있는데, 파일의 종류나 접근 권한, 크기, 소유자, 파일 변경 시각, 데이터 블록 수 이런 정보들이 들어있다. (아이노드 정보를 검색하려면 stat. 파일 정보를 검색할 때 가장 많이 쓰는 함수도 stat이다. stat 함수로 검색한 아이노드 정보는 stat 구조체에 저장되어 리턴된다. 그냥 바로 나오는 거 아님!)
파일이나 디렉터리에 접근하는 방법 - 하드 링크와 심벌릭 링크. 하드 링크는 아이노드가 똑같은 파일을 새로 생성(아이노드에 저장된 링크 개수는 증가)한다. 심벌릭 링크는 윈도우에서 바로가기 기능. 기존 파일과 다른 아이노드를 쓰고, 기존 파일의 경로를 저장해서 가르키고 있는 것. 어떤 파일에 걸려있는 모든 아이노드를 끊는다는 것은 곧 파일을 삭제하는 것과 같다.
파일을 읽고 쓰기 - 파일을 읽고 쓰려면 파일 디스크립터(fd)를 이용한다. 파일 디스크립터는 현재 열려 있는 파일을 구분하려고 붙인 번호인데, 0번 1번 2번... 이런 식으로 지정된다. 파일을 열었으면 꼭 닫아야한다. 하나의 프로세스가 열 수 있는 파일 개수 정해짐.. 파일을 읽고 쓰고 하다 보면 현재 읽을 위치나 쓸 위치를 알려줘야 하는데 이런 위치를 알려주는 것이 오프셋이다. 저수준의 파일 입출력에서는 fd를 쓰지만 고수준의 파일 입출력에서는 파일 포인터를 쓴다.
2. 프로세스 다루기
프로세스는 현재 실행 중인 프로그램. 각 프로세스에는 뭐가 뭔지 알기 위해서 번호를 부여하는데 이게 PID이고, 0번 프로세스는 커널의 일부분인 스케줄러다. 프로세스에는 부모와 자식이 있는데, 모든 프로세스에는 자신을 생성한 부모(PPID)가 있다. (프로그램 안에서 다른 프로그램을 실행해서 생성하는 경우) 새로운 프로세스를 생성할 때에는 folk() 를 쓴다. (folk는 부모 프로세스를 복붙해서 자식 프로세스 만드는 방법) 대신 이렇게 만들면 자식, 부모 둘다 동시에 동작되므로 부모가 먼저 종료해버리면 자식 혼자 남아서 좀비가 되는 등의 문제점이 생길 수 있다. (프로세스 동기화가 필요)
3. 프로세스 통신
프로그램을 실행하는 과정에서 프로세스끼리 통신이 필요한 경우에는 어떻게 할까? 메모리 매핑을 이용하는 방법, 파이프를 이용하는 방법 등등이 있다. 간단한 통신 중에 하나는 '시그널'인데, 프로세스끼리 주고받는 간단한 메세지(인터럽트)이다. 시그널은 미리 정해진 숫자가 있고, 시그널을 받은 프로세스는 무시하거나 미리 시그널을 받을 때 해야할 매뉴얼을 보고(시그널 핸들러) 움직이거나, 미뤘다가 시그널을 볼 수도 있다.
복잡한 통신에서 프로세스1과 2가 서로 데이터를 주고받으면서 작업을 해야하는 경우에는 통신 프로그래밍이 필요하다. 동일한 시스템 안에 있는 프로세스끼리 데이터를 주고받을 때(IPC, 프로세스 간 통신) : 메모리 매핑, 공유 메모리 이용, 세마포어.. 파이프.. 등이 있다. 다른 시스템 안에 속한 프로세스끼리 데이터를 주고받거나 통신해야 할 때: 네트워크를 이용한 통신으로 TCP/IP 프로토콜을 기본으로 하며 소켓 라이브러리를 이용한다.
메모리 매핑은 프로세스 메모리 안에 파일 내용을 저장해서 쓰는 것이고 mmap() 함수를 사용한다. 메모리에 매핑되면 파일 입출력 함수를 쓰지 않아도 직접 읽고 쓸 수 있다. 매핑된 파일은 동기화를 잘해줘야 한다. 파이프는 한 방향으로만 흐르는 통이다. 양방향 통신을 하려면 파이프 2개 필요. 세마포어랑 뮤텍스 부분은 다시 복습해서 정리해야해서 패스.
소켓 프로그래밍은 네트워크 지식이 쫌 필요. TCP/IP 중 전송계층에 TCP와 UDP 프로토콜로 나뉜다. TCP는 세번 악수하면서 신중하게 정보가 왔다갔다 하는 거고 UDP는 정보를 막 뿌리는 거였는데, 응용 계층이랑 전송 계층 사이에 소켓이 붙어서 엄청 간단하게 전송계층의 기능을 사용할 수 있게 해준다. 소켓에도 TCP/UDP 둘 중 하나를 정해야하고(STREAM-TCP, DGRAM-UDP)
세부적인 문법이나 함수 사용법, 그리고 실습파일들이 있었는데 그거까지는 도저히 하루 안에 받아들이기는 어려울 것 같다. 강의만으로는 문맥을 이해하기가 힘들어서 책 시스템 프로그래밍 리눅스&유닉스를 참고해서 정리했다. 이거 실습한다고 aws 인스턴스의 우분투 켜놓았는데 도저히 시간이 안났다. 하하 실습파일은 나중에 해보는 걸로!!
'공부방 > Upstage AI Lab 4기' 카테고리의 다른 글
리눅스에 익숙해지기 (0) | 2024.07.26 |
---|---|
부트캠프 현직자, 수료생 특강 (0) | 2024.07.26 |
7/24 학습일지 | aws 인스턴스 우분투 환경에서 리눅스 명령어 익히기 (2) | 2024.07.25 |
7/23 학습일지 | 논리적 사고력 기르기, 알고리즘 (10) | 2024.07.25 |
7/22 학습일지 | 알고리즘을 위한 논리적인 사고력 기르기 실습 (1) | 2024.07.22 |