1 / 51

11. Interprocess Communication

11. Interprocess Communication. The Design of The Unix Operating System, Maurice J. Bach. Contents. 11.1 Process Tracing 11.2 System V IPC 11.2.1 Messages 11.2.2 Shared Memory 11.2.3 Semaphores 11.2.4 General Comments 11.3 Network Communications 11.4 Sockets.

flo
Télécharger la présentation

11. Interprocess Communication

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 11. Interprocess Communication The Design of The Unix Operating System, Maurice J. Bach

  2. Contents • 11.1 Process Tracing • 11.2 System V IPC • 11.2.1 Messages • 11.2.2 Shared Memory • 11.2.3 Semaphores • 11.2.4 General Comments • 11.3 Network Communications • 11.4 Sockets

  3. 11.1 Process Tracing • UNIX 시스템은 프로세스들의 트레이싱을 위해 프로세스간 통신의 원시적 형태를 제공하며, 이 기능은 디버깅에 유용하다. • 프로세스 트레이싱은 디버거 프로세스와 트레이스되는 프로세스간을 동기화하고 트레이스되는 프로세스의 수행을 제어하는 일로 구성된다.

  4. Ptrace 시스템 호출구문 • ptrace (cmd, pid, addr, data); cmd : 데이터 읽기, 데이터 쓰기, 수행 재개 등의 명령 pid : 트레이스되는 프로세스의 프로세스 id addr : 읽혀지거나 쓰여질 자식 프로세스 내의 가상 주소 data : 쓰여질 정수 값

  5. ptrace 사용의 단점 • 커널은 디버거와 트레이스되는 프로세스간에 한 단어의 데이터 전송을 위해 네 번의 문맥 교환을 해야 한다. • 디버거는 자식 프로세스들만 트레이스할 수 있다. • 디버깅되는 프로세스가 ptrace를 불러 커널에게 자신이 트레이스되는 것에 동의한다는 것을 알리지 않았다면, 디버거는 이미 수행되고 있는 프로세스를 트레이스할 수 없다. • Setuid 프로그램을 트레이스할 수 없다.

  6. Killian 의 프로세스 트레이싱을 위한 기법 • 파일 시스템 스위치에 기초 • 관리자가 “/proc”이라는 파일 시스템을 마운트한다;사용자들은 PID로 프로세스들을 확인하고 그 프로세스들을 “/proc”내의 파일로 다룬다. • ptrace의 3가지 단점 제거 • 빠르다. • 디버거는 임의의 프로세스들을 트레이스할 수 있다. • 트레이스되는 프로세스는 트레이싱이 가능하도록 미리 약속해 둘 필요가 없다.

  7. 11.2 System V IPC • UNIX 시스템 V IPC 패키지는 세가지 메커니즘으로 이루어져 있다. • 메시지 : 프로세스들로 하여금 임의의 프로세스들에게 포맷된 데이터 스트림을 보내도록 한다. • 공유 메모리 : 프로세스들이 가상 주소 공간의 일부를 공유하도록 한다. • 세마포어 : 프로세스들이 수행을 동기화 하도록 한다.

  8. 공통 성질 • 각 메커니즘은 테이블을 가지며, 이 테이블의 항들은 해당 메커니즘의 모든 인스턴스를 기술한다. • 각 항은 숫자 키를 가지는데, 이것은 사용자가 선택한 이름이다. • 각 메커니즘은 “get”시스템 호출을 가지는데, 이것은 새로운 항을 만들거나 존재하는 항을 검색하기 위한 것이다.

  9. 각 IPC 메커니즘에 대해, 커널은 다음과 같은 공식을 사용하여 디스크립터로부터 데이터 구조 테이블의 인덱스를 찾는다 : 인덱스 = 디스크립터 modulo (테이블에 있는 항의 개수) • 각 IPC 항은 허가 구조(permissions structure)를 가진다. • 각 항은 상태 정보를 포함한다. • 각 메커니즘은 “control”시스템 호출을 가지는데, 이 시스템 호출은 한 항의 상태를 묻거나, 상태 정보를 set 하거나, 시스템으로부터 항을 제거한다.

  10. 11.2.1 Messages • 네 개의 시스템 호출이 있다. • msgget : 다른 시스템 호출에서 사용할 메시지 큐를 가리키는 메시지 디스크립터를 복귀한다(생성할 수도 있다.) • msgctl : 메시지 디스크립터와 관련된 인수들을 세팅하고 복귀할 수 있는 옵션과, 디스크립터를 제거할 수 있는 옵션을 포함한다. • msgsnd : 메시지를 보내는 시스템 호출이다. • msgrcv : 메시지를 받는 시스템 호출이다.

  11. Msgget 시스템 호출 구문(syntax) • msgqid = msgget (key, flag); • msgqid : 호출에 의해 복귀되는 디스크립터 key : 찾고자 하는 항 flag : 주어진 키를 갖는 항이 존재하지 않으면 새로 운 항을 만들 것인지, 주어진 키를 갖는 항이 이미 존재하면 에러를 알려줄 것인지 등에 대 한 것을 지정

  12. 커널은 메시지들을 각 디스크립터에 연관된 연결리스트(queue)에 저장하고, msgqid를 메시지 큐 헤더들의 배열에 대한 인덱스로 사용한다. • 일반적인 IPC 허가 필드 외에 큐 구조는 다음의 필드들을 추가로 가진다. • 연결 리스트의 처음 메시지와 마지막 메시지를 가리키는 포인터 • 연결 리스트에 있는 메시지 개수와 전체 데이터 바이트의 수 • 연결 리스트에 존재할 수 있는 데이터 바이트의 최대 수 • 메시지를 보내고 받는 바로 이전 프로세스들의 프로세스 ID들 • 바로 이전 msgsnd, msgrcv, msgctl 연산의 시간 스탬프들

  13. Msgsnd 시스템 호출 구문 • msgsnd (msgqid, msg, count, flag) • msgqid : msgget 호출에 의해 복귀된 메시지 큐의 디스크립터 msg : 사용자가 선택한 정수형(integer type)과 문자 배열로 구성된 구조에 대한 포인터 count : 전송할 데이터 배열의 크기 flag : 내부 버퍼 공간이 다 소모되었을 경우 커널이 취해야 할 행동(action)

  14. 알고리즘 msgsnd 입력 : (1) 메시지 큐 디스크립터 (2) 메시지 구조의 주소 (3) 메시지의 크기 (4) 플래그 출력 : 전송한 바이트 수 { 디스크립터의 적법성을 검사하고, 허가를 검사; while(메시지를 저장하기 위한 공간이 충분하지 않으면) { if(기다리지 말라는 플래그가 지정되어 있으면) return; sleep(충분한 공간이 사용가능하다는 사건이 발생할 때까지); } 메시지 헤더를 가져온다; 사용자 공간으로부터 커널 공간으로 메시지 텍스트를 읽는다; 데이터 구조를 조정함 ; 메시지 헤더를 큐에 넣음; 메시지 헤더가 데이터, 카운트, 시간 스탬프, 프로세스 ID 등을 가리키도록 함; 큐로부터 메시지를 읽기 위해서 대기하고 있는 모든 프로세스들을 깨움; }

  15. Msgrcv 시스템 호출 구문 • count = msgrcv(id, msg, maxcount, type, flag) • id : 메시지 디스크립터 msg : 수신될 메시지를 저장하기 위한 사용자 구조 의 주소 maxcount : msg 내의 데이터 배열의 크기 type : 사용자가 읽기를 원하는 메시지 유형 flag : 큐에 메시지가 하나도 없을 때 커널이 취해야 할 행동 count : 사용자에게 복귀되는 바이트의 수

  16. Msgctl 시스템 호출 구문 • msgctl (id, cmd, mstatbuf) • id : 메시지 디스크립터 cmd : 명령의 유형 mstatbuf : 제어 인수를 저장하거나, 또는 상태에 대 한 질의 결과를 저장할 사용자 데이터 구 조의 주소

  17. #include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h> #define MSGKEY 75 struct msgform {long mtype; char mtext[256];} msg;int msgid; main(){ int i, pid, *pint; extern cleanup(); for(i=0; i<20; i++) signal(i, cleanup); msgid=msgget(MSGKEY, 0777 | IPC_CREAT); for(;;) { msgrcv(msgid, &msg, 256, 1, 0); pint=(int *)msg.mtext; pid=*pint; printf("server:receive from pid %d\n", pid); msg.mtype=pid; *pint=getpid(); msgsnd(msgid, &msg, sizeof(int), 0); }}cleanup(){ msgctl(msgid, IPC_RMID, 0); exit();}

  18. #include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>#define MSGKEY 75struct msgform { long mtype; char mtext[256];}; main(){ struct msgform msg; int msgid, pid, *pint; msgid=msgget(MSGKEY, 0777); pid=getpid(); pint=(int *)msg.mtext; *pint=pid; msg.mtype=1; msgsnd(msgid, &msg, sizeof(int), 0); msgrcv(msgid, &msg, 256, pid, 0); printf("client:receive from pid %d\n", *pint);}

  19. [root@blue /mydoc]# server server:receive from pid 1882 server:receive from pid 1883 [root@blue /mydoc]# client client:receive from pid 1881 [root@blue /mydoc]# client client:receive from pid 1881

  20. 11.2.2 Shared Memory • 프로세스들은 자신들의 가상 주소 공간의 일부분을 공유하면서, 공유 메모리에 저장된 데이터를 읽고, 또 공유 메모리에 데이터를 기록함으로써 상호 통신할 수 있다. • 공유 메모리를 조작하기 위한 시스템 호출 • Shmget : 공유 메모리의 새로운 영역(region)을 생성하거나, 이미 존재하는 영역을 복귀한다. • Shmat : 프로세스의 가상 주소 공간에 한 영역을 논리적으로 부착 • Shmdt : 프로세스의 가상 주소 공간으로부터 한 영역을 분리 • Shmctl : 공유 메모리에 관계된 여러 인수들을 조작

  21. Shmget 시스템 호출 구문 • shmid = shmget(key, size, flag) • key,flag :msgget 호출에서의 key, flag와 같은 의 미 size : 영역의 바이트 수 shmid : 호출에 의해 복귀되는 공유 메모리 영역의 디스크립터

  22. Shmat 시스템 호출 구문 • virtaddr = shmat (id, addr, flags) • id : shmget 시스템 호출에 의해 복귀된 것으로 공유 메모리 영역을 나타냄 addr : 사용자가 공유 메모리를 부착하고자 하는 주소 flags : 영역을 읽기만(read only) 할 것인지와, 사용자가 지정 한 주소를 커널이 반올림해야(round off) 하는지를 지정 viraddr : 커널이 영역을 부착한 가상 주소 (프로세스가 요청한 값 addr과 일치하지 않을 수도 있다.)

  23. Shmdt 시스템 호출 구문 • shmdt(addr) • addr : 이전의 shmat 호출에 의해 복귀된 가상 주소

  24. Shmctl 시스템 호출 구문 • shmctl (id, cmd, shmstatbuf) • id : 공유 메모리 테이블 항 cmd : 수행할 연산의 유형 shmstatbuf : 사용자 수준의 데이터 구조에 대한 포 인터 (데이터 구조 – 공유 메모리 테이 블 항의 상태를 질의하거나 세트할 때 관련된 상태 정보를 저장)

  25. // attach #include <sys/types.h> #include <sys/ipc.h>#include <sys/shm.h>#define SHMKEY 75#define K 1024int shmid;main(){ int i, *pint; char *addr1, *addr2; extern char *shmat(); extern cleanup(); for(i=0; i<20; i++) signal(i, cleanup); shmid=shmget(SHMKEY, 128*K, 0777|IPC_CREAT); addr1=shmat(shmid, 0, 0); addr2=shmat(shmid, 0, 0); printf("addr1 0x%x addr2 0x%x\n", addr1, addr2); pint=(int *)addr1; for(i=0; i<256; i++) *pint++=i; pint=(int *)addr1; *pint=256; pint=(int *)addr2; for(i=0; i<256; i++) printf("index %d\tvalue %d\n", i, *pint++); pause();}cleanup(){ shmctl(shmid, IPC_RMID, 0); exit();}

  26. // share #include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#define SHMKEY 75#define K 1024int shmid;main(){ int i, *pint; char *addr; extern char *shmat(); shmid=shmget(SHMKEY, 64*K, 0777); addr=shmat(shmid, 0, 0); pint=(int *)addr; while(*pint==0) ; for(i=0; i<256; i++) printf("%d\n", *pint++);}

  27. [root@blue /mydoc]# attachaddr1 0x4010b000 addr2 0x4012b000index 0 value 256index 1 value 1index 2 value 2index 3 value 3… [root@blue /mydoc]# shared256123… 255

  28. 11.2.3 Semaphores • 프로세스는 세마포어 시스템 호출을 통해 세마포어 집합에 원자적인(atomically) 연산을 행함으로써 수행을 동기화 시킨다. • UNIX 시스템에서 세마포어는 다음의 요소들로 구성된다. • 세마포어 값 • 세마포어를 가장 나중에 조작한 프로세스 ID • 세마포어 값이 증가하기를 기다리는 프로세스들의 수 • 세마포어 값이 0이 되도록 기다리는 프로세스들의 수

  29. 세마포어 시스템 호출 • semget : 세마포어 집합들을 생성하고 접근을 얻음 • semctl : 세마포어 집합에 대해 여러 제어연산을 행 함 • semop : 세마포어 값들을 조작

  30. Semget 시스템 호출 구문 • 세마포어들의 배열을 생성 • id = semget (key, count, flag) • key, flag, id : 메시지, 공유 메모리에 대한 인수들과 비슷 count : 세마포어 배열의 원소 개수

  31. Semop 시스템 호출 구문 • oldval = semop (id, oplist, count) • id : semget에 의해 복귀되는 디스크립터 oplist : 세마포어 연산들의 배열을 가리키는 포인터 count : 세마포어 연산들의 배열의 크기 oldval : 이번 연산이 행해지기 전에, 집합내의 세마포어중 제 일 마지막 연산이 행해졌던 세마포어의 값 • Oplist의 각 원소의 형식 • 현재 연산이 행해지는 세마포어 배열 항을 나타내는 세마포어 번호 • 연산 • 플래그들

  32. Semctl 시스템 호출 구문 • semctl(id, number, cmd, arg) • Arg 는 다음과 같은 union으로 선언된다. • Union semunion { int val; struct semid_ds *semstat; unsigned short *array; } arg; • id : 세마포어 id number : 세마포어 번호 cmd : 명령어

  33. 11.2.4 General Comments • 파일 시스템과 IPC 메커니즘 사이에는 몇가지 공통점이 있다. • “Get”시스템 호출은 creat와 open 시스템 호출과 비슷하다. • “control”시스템 호출은 시스템으로부터 디스크립터를 제거하는 옵션을 가지고 있으며, 이는 unlink 시스템 호출과 유사하다. • 파일 시스템의 close와 유사한 것은 없다. • IPC 메커니즘은 전통적이며 전 시스템에 퍼져 있는 파일 대신에, 새로운 차원의 이름 공간인 키(key)를 도입했다.

  34. 11.3 Network Communications • Mail, 원격 파일 전송, 원격 로그인과 같이 다른 기계와 통신을 하고자 하는 프로그램들은 역사적으로 연결을 설정하고 데이터를 교환하기 위하여 임기응변적인 방법들을 사용하여 왔다. • 전형적인 mail 프로그램들은 mail 메시지의 내용을 특별한 파일에 저장하여 전달했다. • 다른 기계 상으로 mail을 보내려면 로칼 프로세스는 기계간의 경계를 넘어서 원격 대리인(agent)과 통신할 방법이 필요하게 된다. • 로칼 프로세스는 클라이언트라 불리며 원격 프로세스는 서버라고 불린다.

  35. 네트워크 통신은 UNIX 시스템에 문제를 제기하였는데, 왜냐하면 메시지가 데이터와 제어 부분을 포함해야 되기 때문이었다. • 이것은 프로세스들이 어떤 종류의 네트워크와 이야기를 주고 받고 있나 하는 것을 알아야 하므로, 모든 장치를 파일처럼 보이게 함으로써 사용자가 파일의 유형을 의식할 필요가 없다는 원칙에 위배된다.

  36. 네트워크 통신을 구현하기 위한 전통적인 방법들은 제어 정보를 명시하기 위하여 ioctl 시스템 호출에 많이 의존하였으나, 그 사용법은 네트워크 유형에 따라서 일정하지가 않다. • 따라서, 이는 한 네트워크를 위하여 고안된 프로그램이 다른 네트워크에서는 사용될 수 없다는 부작용을 갖게 한다. • 시스템 V 최근 버전에 구현된 스트림은 프로토콜 모듈들이 열린 스트림에 push되어 융통성있게 결합될 수 있도록 하고, 또한 이들의 사용은 사용자 수준에서 일관성을 갖기 때문에, 네트워크 지원을 위하여 좋은 메커니즘을 제공한다.

  37. 11.4 Sockets • 프로세스간 통신에 공통적인 방법들을 제공하고, 또한 복잡한 네트워크 프로토콜들의 사용을 허용할 수 있도록, BSD 시스템은 소켓이라는 메커니즘을 제공한다. • 커널 구조는 소켓층, 프로토콜층, 장치층의 3부분으로 구성된다. • 소켓층 : 시스템 호출과 그 하위층들간의 인터페이스를 제공한다. • 프로토콜층 : 통신에서 사용되는 프로토콜 모듈들을 포함하고 있다. • 장치층 : 네트워크 장치들을 제어하는 장치 드라이버들을 포함하고 있다.

  38. 프로세스들은 클라이언트-서버 모델을 사용하여 통신을 하는데, 서버 프로세스는 양방향 통신 통로의 한쪽 끝인 소켓에 귀를 기울이고 있고, 클라이언트 프로세스들은 양방향 통로의 다른쪽 끝인 또 다른 소켓을 통하여 서버 프로세스와 통신한다. • 커널은 내부적 연결들을 관리하며, 데이터를 클라이언트에서 서버로 전달한다.

  39. 지명 약정(naming convention)과 프로토콜 주소 포맷과 같은 공통적인 통신 특성들을 공유하는 소켓들은 도메인으로 묶여진다. • 4.2 BSD 시스템은 동일한 기계상에서의 프로세스들간의 통신을 위하여 “UNIX 시스템 도메인”을 지원하고, DARPA 통신 프로토콜을 사용하는 네트워크상에서의 프로세스 통신을 위해서는 “인터네트 도메인”을 지원한다. • 각 소켓은 가상 회로 혹은 데이타그램 중 한 타입을 갖는다.

  40. 소켓 메커니즘에는 몇가지 시스템 호출이 있다. • Socket : 한 통신 링크의 끝점(end point)을 설정한다. • Bind : 하나의 이름을 소켓 디스크립터에 연관시킨다. • Connect : 커널로 하여금 이미 존재하는 소켓과 연결을 만들도록 요청한다. • Listen : 최대 큐 길이를 지정한다. • Accept : 서버 프로세스와의 연결 요청을 받아들인다. • Send 와 recv : 연결된 소켓을 통하여 데이터를 전송한다. • Shutdown : 소켓 연결을 종료시킨다. • Getsockname : 이전의 bind 호출에 의하여 지정된 소켓의 이름을 얻는다.

  41. Socket 시스템 호출 구문 • sd = socket(format, type, protocol) • format : 통신 도메인을 규정 type : 소켓을 통한 통신 타입을 규정 protocol : 통신을 제어할 프로토콜을 규정 • Bind 시스템 호출 구문 • bind(sd, address, length) • sd : 소켓 디스크립터 address : socket 시스템 호출에서 규정된 통신 도메인과 프로 토콜 고유의 식별자를 규정하는 구조를 가리킴 length : address 구조의 길이

  42. Connect 시스템 호출 구문 • connect(sd, address, length) • sd, length : bind 에서와 동일 address : 통신선의 다른쪽을 구성하는 목표 소켓 주소 • Listen 시스템 호출 구문 • listen(sd, qlength) • sd : 소켓 디스크립터 qlength : 해결되지 않은 요구의 최대 개수

  43. Accept 시스템 호출 구문 • nsd = accept(sd, address, addrlen) • sd : 소켓 디스크립터 address : 사용자의 데이터 배열을 가리킴 addrlen : 사용자 배열의 크기 nsd : accept 호출에 의해 복귀되는 sd와는 다른 새로운 소켓 디스크립터

  44. Send 시스템 호출 구문 • count = send(sd, msg, length, flags) • sd : 소켓 디스크립터 msg : 전송되고 있는 데이터를 가리키는 포인터 length : 데이터의 길이 flags : 데이터를 “out-of-band”로 보내기 위하여 SOF_OOB 값으로 세트할 수 있다. count : 실제 전송된 바이트 수

  45. Recv 시스템 호출 구문 • count = recv(sd, buf, length, flags) • sd : 소켓 디스크립터 buf : 들어오는 데이터를 위한 데이터 배열 length : 예상되는 길이 flags : 들어오는 메시지를 “peek”하여 그 내용을 큐 에서 제거하지 않고 검사하도록 설정되거나, “out of band”데이터를 수신하도록 설정될 수 있다. count : 사용자 프로그램에 복사된 바이트 수

  46. Shutdown 시스템 호출 구문 • Shutdown(sd, mode) • sd : 소켓 디스크립터 mode : 보내는 쪽, 받는 쪽, 혹은 양쪽 모두에 더 이 상의 데이터 전송을 허용하지 않음을 나타 낸다. • Getsockname 시스템 호출 구문 • Getsockname(sd, name, length)

  47. // unix.h #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #define UNIXSTR_PATH "./s.unixstr“ #define UNIXDG_PATH "./s.unixdg“ #define UNIXDG_TMP "/tmp/dg.XXXXXX“ char *pname;

  48. // socket client #include "unix.h“ main(int argc, char *argv[]) { int sockfd, servlen; struct sockaddr_un serv_addr; pname=argv[0]; bzero((char *)&serv_addr, sizeof(serv_addr)); serv_addr.sun_family = AF_UNIX; strcpy(serv_addr.sun_path, UNIXSTR_PATH); servlen=strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); if((sockfd=socket(AF_UNIX, SOCK_STREAM, 0)) < 0) printf("client: can't open stream socket"); if(connect(sockfd, (struct sockaddr *)&serv_addr, servlen) < 0) printf("client: can't connect to server"); write(sockfd, "hi guy\0", 7); close(sockfd); exit(0); }

  49. // socket server #include "unix.h“ main(int argc, char *argv[]) { int sockfd, newsockfd, clilen, childpid, servlen; struct sockaddr_un cli_addr, serv_addr; char buf[256]; pname = argv[0]; if((sockfd=socket(AF_UNIX, SOCK_STREAM, 0)) < 0) printf("server: can't open stream socket"); bzero((char *)&serv_addr, sizeof(serv_addr)); serv_addr.sun_family = AF_UNIX; strcpy(serv_addr.sun_path, UNIXSTR_PATH); servlen=strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family); if(bind(sockfd, (struct sockaddr *)&serv_addr, servlen) < 0) printf("server: can't bind local address"); listen(sockfd, 5);

  50. for( ; ; ) { clilen = sizeof(cli_addr); newsockfd=accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); if(newsockfd < 0) printf("server: accept error"); if((childpid=fork()) < 0) printf("server:fork error"); else if (childpid==0) { close(sockfd); read(newsockfd, buf, sizeof(buf)); printf("server read '%s'\n", buf); exit(0); } close(newsockfd); } }

More Related