💡 프로세스는 시스템내에서 독립적으로 실행되기도 하고 데이터를 주고받으며 협업하기도 한다. 프로세스 간 통신은 데이터를 주거나 받는 동작으로 이루어지며, 이는 쓰기 연산과 읽기 연산으로 간소화할 수 있다.
- 모든 통신에 관련된 연산은
open()
, read()
, write()
, close()
구조이다.
- 전역 변수, 파일을 사용하여 통신은, 운영체제의 도움없이 진행되는 통신 방식
- 파이프, 소켓, 원격 프로시저 호출등은, 운영체제가 제공하는 통신 방식
1.1 프로세스간 통신의 개념
- 프로세스 내부 데이터 통신: 하나의 프로세스 내에 2개 이상의 스레드가 존재하는 경우의 통신
- e.g. 전역 변수나 파일을 이용
- 프로세스간 데이터 통신: 같은 컴퓨터에 있는 여러 프로세스끼리 통신
- 공용 파일, 파이프를 사용
- 네트워크를 이용한 데이터 통신: 여러 컴퓨터가 네트워크로 연결되어있을 경우 통신
- 소켓, 원격 프로시저 호출을 사용
- 소켓을 사용하는 프로세스간 통신을 네트워킹 이라고 한다.
1.2 프로세스 간 통신의 분류
분류 방식 | 종류 | 예시 |
---|
통신 방향 | 양방향 통신 | 일반적 통신, 소켓 |
| 반양방향 통신 | 무전기 |
| 단방향 통신 | 전역 변수, 파일, 파이프 |
| | |
통신 구현 방식 | 대기가 있는 통신(동기화) | 파이프, 소켓 |
| 대기가 없는 통신(비동기화) | 전역 변수, 파일 |
- 반양방향 통신: 데이터를 양쪽 방향으로 전송할 수 있지만 동시 전송은 불가능하고 특정 시점에 한쪽 방향으로만 전송할 수 있는 구조
- 전역변수를 사용하는 통신 방식의 문제점은, 언제 데이터를 보낼지 받는 쪽에서는 모른다는 것이다.
- 따라서 데이터를 받는 쪽에서 반복적으로 전역변수의 값을 점검해야한다.
- 상태 변화를 살피기 위해 반복문을 실행하며 기다리는 것을 바쁜 대기(busy waiting)이라고 한다.
- 바쁜 대기 문제를 해결하기 위해서 동기화(synchronization)를 사용한다.
- 동기화를 사용하면 바쁜대기를 하지 않아도 데이터가 도착했음을 운영체제가 알려준다.
- e.g. 메신저에서 메세지가 도착했다고 알려주는 알림
1.2.2 동기화 통신 vs 비동기화 통신
- 대기가 있는 통신
- 동기화를 지원하는 방식
- 데이터를 받는 쪽은 데이터가 도착할 때까지 자동으로 대기 상태에 머물러있다.
open()
, close()
함수를 사용한다.
open(
): 키(descriptor)를 받아 작업을 시작
close()
: 자원을 다 사용하면 키를 반납
- 대기가 없는 통신
- 동기화를 지원하지 않는 방식
- 데이터를 받는 쪽은 바쁜 대기를 사용하여 데이터의 도착 여부를 확인한다.
1.2.3 전역 변수를 이용한 통신
- 공동으로 관리하는 메모리를 사용하여 데이터를 주고 받는다.
- 데이터를 보내는 쪽에서는 전역변수나 파일에 값을 쓰고, 데이터를 받는 쪽에서는 전역변수의 값을 읽는다.
- 직접적인 관련이 있는 프로세스간에 사용한다.
- e.g. 부모 프로세스가 전역 변수를 선언한 후 자식 프로세스를 만들면 부모 프로세스와 자식 프로세스가 통신을 할 수 있다.
- 바쁜 대기(busy waiting를 한다.
1.2.4 파일을 이용한 통신
💡 파일 입출력 코드는 크게 open
, write
, read
, close
로 이루어져 있다.
1. 부모-자식 관계 프로세스간 통신에 많이 사용된다.
2. 동기화를 제공하지 않는다.
- 파일 내의 데이터는 한줄로 길게 저장된다. — 순차 파일(Sequential File)
- 순차 파일에 접근 하는 방식을 순차적 접근(Sequential Access)이라고 한다.
- 운영체제가 동기화를 지원하지 않기 때문에, 부모-자식 프로세스 관계라면, 부모 프로세스가
wait()
을 사용하여 자식 프로세스가 작업을 끝낼 때까지 기다렸다가 작업을 시작한다.
read()
와 write()
가 파일 기술자를 공유한다. 따라서 read()
를 하건 write()
를 하건 상관없이 기술자가 전진하여 동기화를 할 수 없다.
파일 열기
open()
을 이용하여 사용하고자 하는 파일이 있는지, 파일이 있다면 쓰기 권한이 있는지 확인
open(”test.txt”, O_RDWR)
O_RDWR
: 읽기/쓰기 작업
O_RDONLY
: 읽기 전용
- 정상적으로 파일을 사용할 수 있다면,
open()
은 fd
를 반환
- fd(File Descriptor)는 어떤 파일에 접근할 수 있는 권한으로, 파일 기술자라고 한다.
- 어떤 파일에 쓰기/읽기 연산을 하려면 먼저
fd
를 얻어야하며 작업이 끝나면 fd
를 돌려줘야한다.
읽기/쓰기 연산
write(fd, ‘Test’, 5)
: 파일에 test를 쓰라는 뜻이다. Test의 크기가 5B이기 때문에 5를 명시
read(fd, buf, 5)
: 파일에서 5B를 읽어 변수 buf에 저장
파일 닫기
close(fd)
: fd가 가리키는 파일을 닫는다.
1.2.5 파이프를 이용한 통신
💡 파이프는 운영체제가 제공하는 동기화 통신 방식으로 단방향이다. 파이프는 이름 있는 파이프와 이름 없는 파이프로 나뉜다.
- 파이프로 양방향 통신을 하려면 파이프 2개를 사용해야한다.
- 파이프에 쓰기 연산을 하면 데이터가 전송되고, 읽기 연산을 하면 데이터를 받는다.
read()
와 write()
의 기술자가 따로 존재한다. 따라서 동기화가 가능하다.
- 파일 기술자를
fd[2]
와 같이 2개의 원소를 가진 배열로 정의하는데, 원소 하나는 읽기용이고 하나는 쓰기용이다.
대기 상태
- 프로세스B가 파이프 1에 대해 읽기 연산을 수행했는데 프로세스 A가 파이프1에 아직 쓰기 연산을 하지 않았다면 프로세스B는 대기 상태가 된다.
- 대기 상태는 프로세스 A가 파이프 1에 데이터를 쓰는 순간 자동으로 풀려 동기화가 이루어진다.
- 프로세스B는 바쁜 대기를 하지 않아도 된다.
이름 없는 파이프
- 일반적인 파이프
- 부모-자식 관계와 같이 서로 관련 있는 프로세스 간 통신에 사용
이름 있는 파이프
- FIFO라 불리는 특수한 파일을 이용하며 서로 관련 없는 프로세스 간 통신에 사용
1.2.5 소켓을 이용한 통신
💡 여러 컴퓨터에 있는 프로세스간 통신은 네트워킹이라고 한다. 네트워킹은 원격 프로시저 호출이나 소켓을 이용한다. 소켓은 프로세스 동기화를 지원하고 양방향 통신이 가능하다.
- 소켓은 하나만 사용해도 양방향 통신이 가능하다.
- 파이프의 경우, 양방향 통신을 하기 위해서는 파이프를 2개 사용해야 한다.
소켓을 사용하여 다른 컴퓨터와 통신을 하려면,
-
IP 주소로 컴퓨터의 위치를 파악한다.
-
원격지의 시스템내 여러 프로세스중 어떤 프로세스와 통신을 할지 결정한다.
- 한 컴퓨터내에는 여러 프로세스가 존재한다.
- 이 때 사용하는 구분 번호를 포트 번호(Port Number)라고 한다.
-
통신하고자 하는 프로세스는, 소켓에 쓰기 연산을 하면 데이터가 전송되고 읽기 연산을 하면 데이터를 받는다.
클라이언트
socket()
connect()
read()/write()
close()
서버
socket()
bind()
- 소켓을 생성한 후, bind()를 사용하여 특정 포트에 새로운 소켓을 등록한다.
- 동시에 여러 클라이언트에 서비스를 하기 위해 하나의 포트번호에 여러개의 소켓을 생성한다.
- 소켓을 하나만 생성한다면 단 한사람에게 서비스를 할 수 있을 것이다.
listen()
accept()
- 클라이언트의 connect(), 즉 연결 요청을 기다리다가 여러명의 클라이언트가 동시에 connect를 하는 경우 그중 하나를 골라서 작업을 한다.
- accept()가 되면 소켓 기술자가 생성되고 작업이 시작된다.
read()/write()
close()
- 작업이 끝나면, 소켓 기술자를 닫는다. 이후에 계속 클라이언트를 받아서 작업해야하기 때문에 무한루프를 돈다.
원격 프로시저 호출
- 다른 컴퓨터에 있는 함수를 호출하는 것
- 소켓을 이용하여 구현
- e.g. 자바같은 객체 지향 언어에서 다른 컴퓨터에 있는 객체의 메소드를 불러와 사용