Home OS Process (3)
Post
Cancel

OS Process (3)

목적


  1. 프로세스의 통신 방법을 다양한 측면에서 실습한다.

실천 목표


  1. 파이프와 POSIX 공유 메모리를 사용하여 프로세스 간 통신을 수행하는 프로그램을 설계한다.
  2. 소켓과 원격 프로시저 호출을 사용하여 클라이언트-서버 통신을 설명한다.
  3. Linux 운영체제와 상호 작용하는 커널 모듈을 설계한다.

IPC 실습 4가지


  1. POSIX 공유 메모리
  2. Mach 운영체제의 메시지 전달 시스템
  3. Windows IPC (공유 메모리 사용)
  4. 파이프 (UNIX의 가장 오래된 IPC 기법)

IPC 실습 (1) POSIX 공유 메모리


  • file과 shared memory 영역을 연관시키는 memory-mapped file를 통해 만들 수 있음
  • Producer Process
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    
          #include <stdio.h>
          #include <stdlib.h>
          #include <string.h>
          #include <fcntl.h>
          #include <sys/shm.h>
          #include <sys/stat.h>
    
          #include <sys/mman.h>
    
          int main()
          {
              /* the size (in bytes) of shared memory object */
              const int SIZE = 4096;
              /* name of the shared memory object */
              const char *name = "OS";
              /* strings written to shared memory */
              const char *message_0 = "Hello, ";
              const char *message_1 = "Shared Memory!\n";
    
              /* shared memory file descriptor */
              int shm_fd;
              /* pointer to shared memory object */
              char *ptr;
    
              /* create the shared memory object */
              shm_fd = shm_open(name, O_CREAT | O_RDWR, 0666);
    			
              /* configure the size of the shared memory object */
              ftruncate(shm_fd, SIZE);
    
              /* memory map the shared memory object */
              ptr = (char *) mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
    
              /* write to the shared memory object */
              sprintf(ptr, "%s", message_0);
              ptr += strlen(message_0);
              sprintf(ptr, "%s", message_1);
              ptr += strlen(message_1);
    
              return 0;
          }
    
  • Consumer Process
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
          #include <stdio.h>
          #include <stdlib.h>
          #include <fcntl.h>
          #include <sys/shm.h>
          #include <sys/stat.h>
    
          #include <sys/mman.h>
    
          int main()
          {
              /* the size (in bytes) of shared memory object */
              const int SIZE = 4096;
              /* name of the shared memory object */
              const char *name = "OS";
              /* shared memory file descriptor */
              int shm_fd;
              /* pointer to shared memory object */
              char *ptr;
    
              /* open the shared memory object */
              shm_fd = shm_open(name, O_RDONLY, 0666);
    
              /* memory map the shared memory object */
              ptr = (char *) mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
    
              /* read from the shared memory object */
              printf("%s", (char *)ptr);
    
              /* remove the shared memory object */
              shm_unlink(name);
    
              return 0;
          }
    

IPC 실습 (2) Mach 운영체제의 메시지 전달 시스템


  • Mach 운영체제(커널)에서 사용하는 메시지 전달
  • 프로세스와 유사하지만 다른 부분이 있는 태스크의 개념 사용
  • 태스크는 프로세스보다 제어 스레드가 많고 관련 자원이 적음
  • 모든 태스크 간 통신을 포함해서 Mach에서 대부분의 통신은 메시지로 수행
  • 포트(Port)라고 하는 메일박스로 메시지를 주고 받음
  • 각 포트에는 여러 송신자가 있을 수 있지만 수신자는 하나만 존재

IPC 실습 (3) Windows IPC (공유 메모리 사용)


  • Windows는 다중 운영 환경 (또는 서브시스템)을 지원
  • 응용 프로그램은 메시지 전달 기법을 통해 서브시스템과 통신
  • 그러므로 응용 프로그램은 서브시스템 서버의 클라이언트로 간주 가능
  • Windows의 메시지 전달 설비는 고급 로컬 프로시저 호출 설비(ALPC, Advanced Local Procedure Call Facilitiy)
  • ALPC는 동일 기계상에 있는 두 프로세스 간의 통신에 사용, 표준 원격 프로시저 호출(RPC) 기법과 같음
  • Windows는 두 프로세스 간 연결을 구축하고 유지하기 위해 연결 포트(Connection Port)와 통신 포트(Communication Port) 사용

IPC 실습 (4) 파이프 (UNIX의 가장 오래된 IPC 기법)


  • 초창기 UNIX의 IPC 메커니즘 중 하나로, 두 프로세스가 통신하도록 하는 배관
  • 단방향도 가능하고, 양방향도 가능한데, 양방향으로는 반이중(half-duplex)만 가능
  • 부모-자식 관계의 프로세스에서만 사용 가능
  • 네트워크 상에서는 사용하지 않음 (네트워크 상에서 사용하는 파이프 개념이 다음으로 배울 소켓임)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    
      #include <sys/types.h>
      #include <stdio.h>
      #include <string.h>
      #include <unistd.h>
    
      #define BUFFER_SIZE 25
      #define READ_END 0
      #define WRITE_END 1
    
      int main(void)
      {
          char write_msg[BUFFER_SIZE] = "Greetings\n";
          char read_msg[BUFFER_SIZE];
          int fd[2];
          pid_t pid;
    
          /* create the pipe */
          if (pipe(fd) == -1) {
              fprintf(stderr, "Pipe Failed");
              return 1;
          }
    
          /* fork a child process */
          pid = fork();
    
          if (pid < 0) { /* error occured */
              fprintf(stderr, "Fork Failed");
              return 1;
          }
    
          if (pid > 0) { /* parent process */
              /* close the unused end of the pipe */
              close(fd[READ_END]);
    
              /* write to the pipe */
              write(fd[WRITE_END], write_msg, strlen(write_msg)+1);
    
              /* close the write end of the pipe */
              close(fd[WRITE_END]);
          } else { /* child process */
              /* close the unused end of the pipe */
              close(fd[WRITE_END]);
    
              /* read from the pipe */
              read(fd[READ_END], read_msg, BUFFER_SIZE);
              printf("Read %s", read_msg);
    
              /* close the read end of the pipe */
              close(fd[READ_END]);
          }
    
          return 0;
      }
    

클라이언트 서버 환경에서 통신 2가지


  1. 소켓
  2. 원격 프로시저 호출 (RPC, Remote Procedure Call)

클라이언트 서버 환경에서 통신 (1) 소켓


  • 소켓은 일종의 파이프인데, 네트워크에서 사용하기 위해 IP와 Port가 바인딩되어 있는 것
  • 엄밀하게는, 커뮤니케이션을 위한 두 종단을 의미
  • Data Server
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    
          package os.concepts;
    
          import java.io.IOException;
          import java.io.OutputStream;
          import java.io.PrintWriter;
          import java.net.ServerSocket;
          import java.net.Socket;
          import java.text.DateFormat;
          import java.text.SimpleDateFormat;
          import java.util.Date;
    
          public class DateServer {
              public static void main(String[] args) throws IOException {
                  ServerSocket serverSocket = null;
                  int port = 7777;
    
                  try {
                      /* 서버 소켓 생성 후 7777번 포트와 결합 */
                      serverSocket = new ServerSocket(port);
                      System.out.printf("%s 서버가 준비되었습니다.\n", getTime());
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
    
                  while (true) {
                      System.out.printf("%s 연결요청을 기다립니다.\n", getTime());
                      /* 서버 소켓은 클라이언트의 연결요청이 올 때까지 실행을 멈추고 기다림 */
                      /* 클라이언트의 연결요청이 들어오면 클라이언트 소켓과 통신할 새로운 소켓 생성 */
                      Socket socket = serverSocket.accept();
                      System.out.printf("%s %s:%d으로부터 연결요청이 들어왔습니다.\n", getTime(), socket.getInetAddress(), socket.getPort());
    
                      /* 소켓의 출력스트림을 얻음 */
                      OutputStream out = socket.getOutputStream();
                      PrintWriter pout = new PrintWriter(out, true);
    
                      /* 원격 소켓에 데이터를 보냄 */
                      pout.printf("%s Message From Server\n", getTime());
    
                      /* 스트림과 소켓을 닫음 */
                      socket.close();
                      pout.close();
                      out.close();
                  }
              }
    
              private static String getTime() {
                  DateFormat df = new SimpleDateFormat("[hh:mm:ss]");
                  return df.format(new Date());
              }
          }
    
  • Data Client
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    
          package os.concepts;
    
          import java.io.BufferedReader;
          import java.io.IOException;
          import java.io.InputStream;
          import java.io.InputStreamReader;
          import java.net.ConnectException;
          import java.net.Socket;
          import java.text.DateFormat;
          import java.text.SimpleDateFormat;
          import java.util.Date;
    
          public class DateClient {
              public static void main(String[] args) {
                  try {
                      String serverIp = "127.0.0.1";
                      int serverPort = 7777;
    
                      System.out.printf("%s:%d서버에 연결 중입니다.\n", serverIp, serverPort);
    
                      /* 소켓을 생성해서 연결을 요청 */
                      Socket socket = new Socket(serverIp, serverPort);
    
                      /* 소켓의 입력스트림을 얻음 */
                      InputStream in = socket.getInputStream();
                      BufferedReader br = new BufferedReader(new InputStreamReader(in));
    
                      /* 원격 소켓으로부터 받은 데이터 출력 */
                      System.out.printf("%s 서버로부터 받은 메시지\n", getTime());
                      String line = null;
                      while ((line = br.readLine()) != null)
                          System.out.println(line);
    
                      /* 스트림과 소켓을 닫음 */
                      socket.close();
                      br.close();
                      in.close();
                  } catch (ConnectException ce) {
                      ce.printStackTrace();
                  } catch (IOException ie) {
                      ie.printStackTrace();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
    
              private static String getTime() {
                  DateFormat df = new SimpleDateFormat("[hh:mm:ss]");
                  return df.format(new Date());
              }
          }
    

클라이언트 서버 환경에서 통신 (2) 원격 프로시저 호출


  • RPC, Remote Procedure Call
  • 원격에 있는 함수를 호출하는 것
  • 원격 서비스의 가장 보편적인 형태 중 하나
  • 네트워크 시스템 상에 있는 프로세스들 간에 프로시저 콜을 추상화한 것
  • RPC 시스템은 클라이언트에게는 서버의 stub을 제공하며 디테일은 숨기며 서버의 skeleton에 접근하도록 함
  • Marshaling된 인수 또는 반환값을 주고 받으며 데이터를 교환할 수 있도록 함

참고


  1. 운영체제 공룡책 강의 | 주니온 | 인프런 https://www.inflearn.com/course/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EA%B3%B5%EB%A3%A1%EC%B1%85-%EC%A0%84%EA%B3%B5%EA%B0%95%EC%9D%98/dashboard
  2. 운영체제 제 10판Abraham Silberschatz, Peter Baer Galvin, Greg Gagne 저/박민규 역퍼스트북2020년 02월 28일
  3. 운영체제 제 10판 솔루션 https://codex.cs.yale.edu/avi/os-book/OS10/practice-exercises/index-solu.html
This post is licensed under CC BY 4.0 by the author.