삽질의 현장/- 윈도우 시스템

#028_WIndow_System_IPC_파이프(1)

shovelman 2015. 9. 28. 16:04

안녕하세요 삽잡이입니다.


이번 시간에는 IPC 통신 기법중, 파이프에 대해서 배워보겠습니다.


예전에는 네트워크가 느렸기 때문에 

프로세스간 통신을 위해 파이프를 사용했다는데 요즘은 잘 쓰지 않는다고 하네요...

아무튼... 그렇지만 개념이 네트워크에서 사용하는 것과 비슷하다고 하니! 

파이프에 대해서 알아봅시다!


Windows, Linux에서 파이프나 메일슬롯은 파일처럼 다루고자 했다고합니다.

그래서 파일 입출력과는 별개처럼 보이는데 CreateFile, ReadFile 과 같은 함수를 사용합니다.


여담으로는 파이프에 대해 알게 되면,

파일 입출력을 배우지 않아도 똑같이 프로그래밍 할 수 있다네요...

또한, 객체지향에 가면 파일을 직접 가지고 노는 경우는 극히 드물다고 합니다.


왜냐하면, 파일을 직접 가지고 놀게 되면 파일만 가지고 놀아야 되기 때문입니다.

따라서 stream, 직렬화라는 개념을 사용하게 되어서 파일을 직접 다루지 않는다고 합니다.

말 그대로 내가 출력하고 입력하는 장치로만 다룬다고 하네요.

그렇게되면 출력,입력하고자 하는 장치로 만들면

파일 뿐만 아니라 그 외 모든 부분에서 장치가 될 수 있다고 합니다.

그런데 API까지는 객체 지향 개념이 좀 약하게(?) 들어가 있기 때문에

그리고 예전에 만들어졌기 때문에 직접 파일을 다루는 프로그램을 한다고 합니다.


자.... 아무튼... 

우리는 직접 파일을 다루는 프로그램을 위해 지금 이 순간에 있는 것이며...

그 중 파이프를 배워보려고 하는 것입니다.... (방향을 잃지 않기 위해 혼잣말 중...)


'파이프를 파일처럼 다룬다.' 중요하진 않지만... 됬고!

파이프의 개념에 대해 들어가봅시다.


우선 Client부터 소개하겠습니다.


CreateFile은 여기에서 파일 생성이 아닌, '파이프 연결 요청'을 말합니다.



즉, '야! 나 이런 파이프 있으면 접속할래!'라는 뜻을 가지고 있습니다.


파이프라는 자원은 내 local 컴퓨터 뿐만 아니라

MS에서 만든 NetBIOS에 의해서 다른 곳에서도 접근이 가능합니다.


아무튼, 해당 함수의 인자들을 몇몇 소개하자면...

우선 연결하고자 하는 파이프의 이름을 첫번째 인자로 받습니다.

이때 주소 기본 형식은 \(역슬레시)를 사용합니다.

\\는 '로컬 네트워크 상에'라는 뜻을 가지고 있고 그 다음에는 IP 및 ID를 입력합니다.

이때 '.'을 해당 위치에 쓰게 되면 내 컴퓨터라는 뜻을 가지게 됩니다.


정리하자면 파이프를 쓸 때는


 

이처럼 사용하게 되는데, 주소의 경우

'\\컴퓨터이름\\pipe\\경로+이름' 의 형태로 사용하게 됩니다.

다섯번째 인수는 파이프가 존재할 때에만 열겠다는 뜻을 가지고 있습니다.

존재하지 않다면 실패를 반환하겠다는 것이지요...



위에서도 언급했지만, 

IPC 통신은 파일 입출력 함수를 사용해서 데이터를 주고 받는다고 했습니다.

왜냐, MS에서는 파일 입출력을 기반으로 IPC 기법들을 구현했기 때문이죠...

파이프로 연결이 성공했다면 데이터를 주고 받아야되지 않겠습니까?

여기서 두 개의 함수를 사용하게 됩니다.


WriteFile과 ReadFile 함수입니다.


 

WriteFile 함수의 경우 파이프에 데이터를 보낼 때 사용합니다.




ReadFile 함수의 경우 데이터를 읽을 때 사용하겠군요...



파이프도 커널 오브젝트입니다.

즉, 커널이 만들어서 제공해주는 오브젝트로써 OS의 자원이라는 것입니다.

그런데 왜 이름이 파이프일까요? 

진짜 파이프처럼 동작하기 때문입니다.

파이프는 유류, 물 같은 액체를 흘려보낼 때 사용하는 관이지 않습니까?

데이터를 흘려보낼 때 사용하기 때문에 그렇게 이름을 붙였을까요?


파이프는 B에서 물을 흘려보내면 A에서 나오게 됩니다.

A에서 B로 보내고 싶다면? 파이프를 B쪽으로 기울여야겠지요...

여기서 우리가 알 수 있는 사실은, 한쪽으로 기울여야 물이 흐른다는 것입니다.

즉, 프로그래밍상에서 보내고 싶은 방향으로 데이터를 흘리기 위해서 구현을 했어도,

반대로 흘리기 위해서는 또 다시 구현을 해야한다는 것입니다.

보내고 받고 둘 다를 같이 못한다는 뜻이지요... 통신 자체가 안된다는 것입니다.

이것이 바로 파이프의 개념입니다...


또한, 파이프에는 단방향, 양방향 파이프가 있습니다.

WIndows OS에서는 이름 없는 파이프, 이름 있는 파이프를 제공해줍니다.

이름 없는 파이프의 경우 부모 자식간에 통신을 위해 사용됩니다.

반면, 독립적인 프로세스간의 통신을 위해서는 이름 있는 파이프(네임드 파이프)를 사용합니다.


파이프의 특징으로는 서버, 클라이언트라는 개념을 가지고 있다는 것입니다.

이전시간에 배웠던 메시지, WM_COPYDATA의 경우에는

누가 서버, 누가 클라이언트 라는 개념이 없었죠...


서버, 클라이언트 개념을 잠시 생각해보도록 하겠습니다.

서비스를 요청하거나 어떤 대상이나 응답을 주문하는 그 '어떤 것'을 가리켜 우리는 클라이언트라고 부릅니다.

그리고, 이 클라이언트에 응답이나 서비스를 제공해주는 '어떤 것'을 서버라고 부릅니다.

이 서버와 클라이언트 개념이 파이프 서버 모델로 발전하게 된것입니다.


이름있는 파이프는 서버 만드는 방법과 클라이언트를 만드는 방법이 다릅니다.

즉, 정해져있다는 것이지요... '넌 서버!', '난 클라이언트!'

만약 둘 다 하고 싶다면 그 기능을 할 수 있는 두 가지 모두를 만들어야됩니다.

왜 그런지는 위에서 설명을 드렸습니다.

아무튼, 기능이 나누어져 있다는 사실을 기억하시길 바랍니다.


CreateFile을 통해 연결을 시도하고,

파이프의 클라이언트 핸들이 만들어지면 서버가 받아오게 됩니다.


서버를 만들기 위해서는 CreateNamedPipe 함수를 사용하지요...



클라이언트는 CreateFile로 파이프에 접속을 하는 것이구요...

서로 데이터를 주고 받을 때에는 ReadFile, WriteFile 함수를 사용하는 것입니다.


CreateNamedPipe를 통해 네임드 파이프 인스턴스를 만들게 되면

즉, 파이프를 생성하면 write하고 read할 수 있는 파이프 핸들을 받게 됩니다.

이 핸들을 가지고 데이터를 쏘거나 받거나 할 수 있게 됩니다.


서버 하나에 여러개의 클라이언트들이 붙을 수 있으니 파이프를 놓는 수 만큼 핸들이 생기게 됩니다.

클라이언트는 핸들이 하나이지요... 


지금까지 알아보는 파이프의 개념은

네트워크 프로그래밍에서도 비슷하게 사용하니 이해하고 넘어갑시다...


그런데 파이프를 통해 통신한다고 쳐도...

데이터가 언제 들어올지 알까요? 계속 지켜봐야되지요... 

그리고 또 다른 클라이언트가 들어오는 것 또한 지켜봐야합니다..

즉, 작업들이 각각 독립적이라는 소리입니다.


데이터가 들어오는 것, 클라이언트가 들어오는 것 그리고 사용자 메시지를 처리하는 것...

모두 다 독립적입니다.

따라서, 동시 다발적으로 들어오는 작업들을 처리하기 위해서는 어떻게 해야할까요?

여러 방법들이 있겠지만, 쓰레드를 사용하는 것 또한 한 방법이 되겠지요...


아무튼...

다음 시간에 파이프에 대해 조금 더 알아보는 시간을 가지도록 하겠습니다.

네트워크의 기초가 되는 개념인 파이프...

꼭 이해합시다!


이상 삽잡이였습니다!