4-10 IPC

do·2022년 6월 8일
1

API

목록 보기
37/42

Inter-Process Communication (IPC)

프로세스는 각자 독립된 메모리 공간을 가지고 있어 서로 간의 데이터를 공유할 방법이 없다. 그렇기에 나온 방식이 IPC로, 프로세스 간 통신을 하는 방법이다.
프로세스 커널이 제공한 IPC 설비를 이용해 프로세스 간 통신을 할 수 있게 되며, IPC 통신 방법에는 여러 가지가 있다.

공유메모리(Shared Memory)

  • 공유 메모리는 앞서 말한 커널에서 제공하는 통신 설비가 아닌, 데이터 자체를 공유하도록 지원하는 설비이다.
  • 별다른 통신 없이 직접적으로 데이터에 접근하기 때문에 IPC 중 가장 속도가 빠르다.
  • 프로세스가 공유 메모리 할당을 커널에 요청하면, 커널은 해당 프로세스에 메모리 공간을 할당해주며 이후 어떤 프로세스건 해당 메모리 영역에 접근할 수 있다.
  • 단점: 동기화 문제

FIFO(Named Pipe)

  • (익명 PIPE는 하나의 프로세스는 데이터를 쓰기, 다른 하나는 데이터를 읽기만 할 수 있다. 한쪽 방향으로만 통신이 가능한 파이프의 특징 때문에 Half-Duplex 통신이라고 부르기도 한다.)
  • 통신을 위해 이름이 있는 파일을 사용한다.
  • 익명 PIPE와 다르게 FIFO는 부모 프로세스와 무관하게 전혀 다른 모든 프로세스들 사이에서 통신이 가능하다.

메시지 큐(Message Queue)

  • FIFO와 입출력 방식은 동일하지만, FIFO는 데이터의 흐름이라면 메시지 큐는 메모리 공간이라는 차이가 있다. 또 FIFO와 달리, 다수의 프로세스간 메시지를 전달할 수 있다.
  • 메시지 큐에 쓸 데이터에 번호를 붙임으로써 여러 개의 프로세스가 동시에 데이터를 쉽게 다룰 수 있다. 즉, 다수의 프로세스들이 큐에 메시지를 보낼 수 있고 다수의 프로세스들이 큐로부터 메시지를 꺼낼 수 있다.
  • 프로세스간 메시지(블록) 단위의 통신이 가능하도록 운영체제에 의해 제공된다.
  • 송신된 메시지는 운영체제에 의해 순차적으로 적재된다.
  • 클라이언트 프로그램에 의해 수신된 메시지는 운영체제가 삭제한다.
  • 메시지의 접근을 위해서는 키가 필요하다.
  • 장점: 안전하고 OS가 알아서 동기화 해줌, 내부적으로 lock을 사용함
  • 단점: 속도가 느리고 오버헤드가 큼.

공유 메모리 관련 함수

(공유 메모리 목록 확인) ipcs- m

1. shmget() - 공유 메모리 생성

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);

매개변수1 key_t key 시스템에서 공유 메모리를 식별하기 위한 번호
매개변수2 size_t size 공유 메모리의 크기
매개변수3 int shmflg 추가 가능한 옵션
- IPC_CREAT 퍼미션 0666을 설정한다. 첫번째 인수 key에 해당하는 메모리가 없으면 공유 메모리를 생성한다.
- IPC_EXCL 공유 메모리가 있으면 실패를 반환하고 접근하지 못하게 한다.
리턴값
1. int 공유 메모리의 shmid (shared memory ID)
2. -1 실패

2. shmat() - shmid에 공유 메모리 세그먼트를 붙임 (attach)

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmAddr, int shmflg);

매개변수1 int shmid 공유 메모리 식별 변호
매개변수2 const void *shmAddr 붙여넣을 메모리 주소이며, 운영체제에서 자동으로 할당을 원할 경우 NULL로 지정한다.
매개변수3 int shmflg 추가 가능한 옵션
- SHM_RDONLY 공유 메모리를 읽기 전용으로 설정한다.
- SHM_RND 두번째 인자인 shmAddr 값이 NULL이 아닐 경우에만 쓴다. shmAddr을 반올림하여 메모리 경계에 맞춘다.
리턴값
1. void * shmid에 대한 주소
2. -1 실패

3. shmdt() - 프로세스에서 공유 메모리 분리 (detach)

#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void *shmAddr);

매개변수1 const void *shmAddr 분리할 공유 메모리의 주소
리턴값
1. 0 성공
2. -1 실패

4. shmctl() - 공유 메모리 영역 제어

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);

매개변수1 int shmid 공유 메모리 식별 변호
매개변수2 int cmd 제어 명령
- IPC_RMID 지정된 공유 메모리 제거, 구조체 제거
- IPC_SET 공유 메모리 공간에 대한 사용자 권한을 변경한다.
- IPC_STAT 현재 공유 메모리 정보를 buf로 지정한 메모리에 저장한다.
- SHM_LOCK 공유 메모리 세그먼트를 잠근다.
- SHM_UNLOCK 공유 메모리 세그먼트를 잠금 해제한다.
매개변수3 struct shmid_ds *buf 공유 메모리 정보를 구하기 위한 버퍼포인터

struct shmid_ds {
	struct ipc_perm shm_perm;    /* 접근권한 */
	int shm_segsz;               /* 세그먼트의 크기(bytes) */
	time_t shm_atime;            /* 마지막 접근 시간 */
	time_t shm_dtime;            /* 마지막 제거 시간 */
	time_t shm_ctime;            /* 마지막 변경 시간 */
	unsigned short shm_cpid;     /* 생성자의 프로세스의 프로세스 id */
	unsigned short shm_lpid;     /* 마지막으로 작동한 프로세스의 프로세스 pid */
	short shm_nattch;            /* 현재 접근한 프로세스의 수 */
    
	/* 다음은 개별적이다 */
	unsigned short shm_npages;   /* 세그먼트의 크기(pages) */
	unsigned long *shm_pages;
	struct shm_desc *attaches;   /* 접근을 위한 기술자들 */
};
    
/* shm_perm 멤버의 필드들은 아래와 같이 설정할 수 있습니다. */
struct ipc_perm{
	key_t  key;
	ushort uid;                  /* owner의 euid 와 egid */
	ushort gid;
	ushort cuid;                 /* 생성자의 euid 와 egid */
	ushort cgid;
	ushort mode;                 /* 접근 모드의 하위 9 bits */
	ushort seq;                  /* 연속 수(sequence number) */
};

리턴값
1. 0 성공
2. -1 실패

pipe 관련 함수

1. pipe() - 파이프 생성

#include <unistd.h>
int pipe(int pipefd[2]);

매개변수1 int pipefd[2] 크기가 2인 int형 배열
- pipefd[0] 읽기 전용 파이프 (파이프 출구, input stream)
함수 호출 후 fd[0]에 데이터를 입력 받을 수 있는 파일 디스크립터가 담김
- pipefd[1] 쓰기 전용 파이프 (파이프 입구, output stream)
함수 호출 후 데이터를 출력할 수 있는 파일 디스크립터가 담김
리턴값
1. 0 성공
2. -1 실패 errno

2. pipe2() - 파이프 생성 +옵션

#include <fcntl.h>
#include <unistd.h>
int pipe2(int pipefd[2], int flags);

매개변수1 int pipefd[2] 크기가 2인 int형 배열
- pipefd[0] 읽기 전용 파이프 (파이프 출구, input stream)
함수 호출 후 fd[0]에 데이터를 입력 받을 수 있는 파일 디스크립터가 담김
- pipefd[1] 쓰기 전용 파이프 (파이프 입구, output stream)
함수 호출 후 데이터를 출력할 수 있는 파일 디스크립터가 담김
매개변수2 int flags 옵션
- O_CLOEXEC 열린 파일에 close-on-exec 플래그를 설정하고, 새 프로세스를 실행하면 이 파일은 자동으로 닫힌다
- O_DIRECT ’직접 입출력’을 수행하기 위해 파일을 오픈한다.
- O_NONBLOCK 파일을 논블로킹 모드로 오픈한다.
- 0 pipe()와 동일함
리턴값
1. 0 성공
2. -1 실패 errno

메시지 큐 관련 함수

1. msgget() - 메시지 큐 생성

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);

매개변수1 key_t key 시스템에서 식별하는 메시지 큐 번호
매개변수2 int msgflg 옵션
- IPC_CREAT key에 해당하는 메시지 큐가 없으면 큐를 새로 생성하는데 이 때 접근 권한도 함께 부여해야 한다. 그러나 메시지 큐가 있으면 이 옵션은 무시한다.
- IPC_EXCL 메시지 큐가 있으면 실패라는 의미로 -1 반환. 이 값이 설정되지 않으면 기존 메시지 큐에 접근해 식별자를 반환한다.
리턴값
1. int 메시지 큐 식별자
2. -1 실패

2. msgsnd() - 메시지 큐에 메시지를 전송

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

매개변수1 int msqid 메시지 큐 식별자
매개변수2 const void *msgp 전송할 메시지
매개변수3 size_t msgz 메시지 크기
매개변수4 int msgflg 옵션
- IPC_NOWAIT 메시지 큐가 가득 차 있어 메시지를 더 이상 저장할 수 없을 경우 실패로 -1 반환. 이 값을 설정하지 않으면 메시지 큐가 메시지를 저장할 수 있을 때까지 대기
리턴값
1. 0 성공
2. -1 실패 errno

3. msgrcv() 메시지 큐에 메시지를 수신

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

매개변수1 int msqid 메시지 큐 식별자
매개변수2 void *msgp 메시지를 수신할 곳 (메시지를 저장할 주소)
매개변수3 size_t msgz 메시지 크기
매개변수4 long msgtyp 메시지 타입
- 0 메시지 큐에서 첫번째 메시지를 수신
- 양수 메시지 큐에서 msgtyp으로 지정한 유형과 같은 메시지를 읽어온다.
- 음수 메시지 유형이 msgtyp으로 지정한 값의 절대값과 같거나 작은 메시지를 읽어온다.
- ex) 3개의 메시지 형식이 1, 5, 9 일 경우에, msgtyp가 -10일 경우 절대값 10보다 작거나 같은 메시지 형식을 갖는 메시지 모두 해당한다. 이 중 가장 작은 1 메시지 형식으로 갖고 있는 메시지 수신
매개변수5 int msgflg 옵션
- 0 블록 모드. 메시지가 올 때 까지 기다린다.
- IPC_NOWAIT 비블록 모두. 메시지 큐에 메시지가 없으면 실패로 -1 반환. 이 값을 설정하지 않으면 메시지가 큐에 도착할 때까지 대기
- MSG_NOERROR 메시지 크기가 msgsz보다 클 때 초과되는 부분을 자른다. 이 값을 설정하지 않으면 -1 반환.
리턴값
1. ssize_t 수신한 메시지 크기
성공하면, msqid_ds에서 msg_qnum이 1 감소, msg_lrpid는 msgrcv함수를 호출한 프로세스의 ID로 설정된다.
2. -1 실패 errno

4. msgctl() - 메시지 큐 제어 (제거/상태 정보 설정 및 읽음)

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgctl(int msqid, int cmd, struct msqid_ds *buf);

매개변수1 int msqid 메시지 큐 식별자
매개변수2 int cmd 수행할 제어 기능
- IPC_STAT 현재 메시지 큐의 정보를 buf로 지정한 메모리에 저장함 msgctl(msqid, IPC_STAT, &buf);
- IPC_SET 메시지 큐의 정보를 buf에 저장한 값으로 변경. 단 msg_perm과 msg_qbtye멤버에 대한 정보만을 변경 가능. 변경은 root 또는 effective ID만 가능함 msgctl(msqid, IPC_SET, &buf);
- IPC_RMID 메시지 큐를 제거하고 관련 데이터 구조체를 제거한다. 이때 세번째 인수인 buf는 0으로 지정 msgctl(msqid, IPC_RMID, 0);
매개변수3 struct msqid_ds *buf 제어 기능에 사용되는 메시지 큐 구조체의 주소

struct msqid_ds {
	struct ipc_perm msg_perm;     /* Ownership and permissions */
	time_t msg_stime;             /* Time of last msgsnd(2) */
	time_t msg_rtime;             /* Time of last msgrcv(2) */
	time_t msg_ctime;             /* Time of last change */
	unsigned long	__msg_cbytes; /* Current number of bytes in queue (nonstandard) */
	msgqnum_t msg_qnum;           /* Current number of messages in queue */
	msglen_t msg_qbytes;          /* Maximum number of bytes allowed in queue */
	pid_t msg_lspid;              /* PID of last msgsnd(2) */
	pid_t msg_lrpid;              /* PID of last msgrcv(2) */
};

리턴값
1. 0 성공
2. -1 실패

키 관련 함수

1. ftok() - System V IPC에서 사용할 key 생성

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);

매개변수1 const char *pathname 실제로 존재하고 access 가능한 파일 또는 디렉토리
- 상대 path이든 절대 path이든 실제로 같은 디렉토리
- 파일이면 pathname의 문자열이 달라도 같이 인식됨
- 파일이 존재해야 하는 이유는 stat으로부터 st_dev, st_ino를 얻기 위해서임
- ex) /usr/downman/data 와 ~/data가 실제 같은 디렉토리이면 같은 값임
매개변수2 int proj_id 같은 path에 대해 구분하기 위한 값으로 하위 8bit값만 사용됨 (1~255)
- 0은 사용할 수 없으며, 하위 8bit만 사용되므로 ‘M’, ‘S’ 등과 같이 문자를 사용할 수 있음
리턴값
1. key_t 0 이상 정상적으로 생성된 key값 (IPC 객체를 생성할 때 사용됨)
2. -1 실패 errno

0개의 댓글