웬디의 기묘한 이야기

글 작성자: WENDYS
반응형


PIPE Server

프로세스 간 통신(Inter-Process Communication, IPC) 기법 중 하나인 PIPE 통신 입니다.


Pipe는 프로세스간에 바이트 스트림을 전송하기 위한 통로의 개념으로 로컬 통신으로 사용하기가 아주 편리한 기법 입니다. (소켓을 이용할수도 있겠지만 로컬 통신에선 포트까지 열어야하는 부담이 있기때문에 비교적 부담이 적은 Pipe를 사용합니다)

Pipe는 Named Pipe와 Anonymous Pipe로 나뉘어지며, IPC에선 주로 Named Pipe가 사용됩니다.
* Anonymous pipe는 사용성이 불편하고, 비동기 및 양방향 입출력이 지원되지 않는 구식 방식이기 때문입니다.


서버에서 하는 역할을 보겠습니다.


[초기화]
1. CreateNamedPipe 를 이용하여 Pipe 서버를 생성
2. ConnectNamedPipe 를 이용하여 Client 접속 대기


[사용]

- client data read
- client data write



[종료]
3. FlushFileBuffers로 통신중이던 버퍼를 비우고
4. DisconnectNamedPipe로 Pipe 서버를 닫고
5. CloseHandle로 Pipe Handle을 닫습니다.


이처럼 간단하게 파이프 서버를 작성할 수 있습니다.



namespace pipe {
class server {

public:
    server(
        __in LPCTSTR pipe_name,
        __in const size_t max_instances,
        __in_opt SECURITY_ATTRIBUTES* secutiry_attributes = nullptr
        ) : _pipe(INVALID_HANDLE_VALUE), _max_instances(max_instances) {

        do {
            if (pipe_name == nullptr || max_instances <= 0) {
                break;
            }

            _pipe = ::CreateNamedPipe(
                pipe_name,
                (PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED),
                (PIPE_TYPE_MESSAGE | PIPE_WAIT),
                static_cast<DWORD>(_max_instances), // max instances
                0, 0, 0,
                secutiry_attributes
                );

            if (_pipe == INVALID_HANDLE_VALUE) {
                break;
            }

        } while (false);
    }

    ~server() {
        disconnect();
    }

    bool accept() {
        bool result = false;

        do {
            
            //
            // Wait for the client to connect; if it succeeds, the function returns a nonzero value.
            // If the function returns zero, GetLastError returns ERROR_PIPE_CONNECTED. 
            //

            BOOL connected = ::ConnectNamedPipe(_pipe, nullptr);
            if (! (connected ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED)) ) {
                break;
            }

            result = true;

        } while (false);

        return result;
    }

    bool read(
        __out size_t& bytes_read,
        __out void* read_buffer,
        __in const size_t read_buffer_size
        ) {

        bool result = false;
        DWORD real_bytes_read = 0;

        do {
            if (!ReadFile(
                _pipe,
                read_buffer,
                static_cast<DWORD>(read_buffer_size),
                &real_bytes_read,
                nullptr)
                ) {
                break;
            }

            if (real_bytes_read == 0) {
                break;
            }

            bytes_read = real_bytes_read;
            result = true;
        } while (false);

        return result;
    }

    bool write(
        __out size_t& bytes_written,
        __in void* write_data,
        __in const size_t write_data_size
        ) {

        bool result = false;
        DWORD real_bytes_written = 0;

        do {
            if (!WriteFile(
                _pipe,
                write_data,
                static_cast<DWORD>(write_data_size),
                &real_bytes_written,
                nullptr)
                ) {
                break;
            }

            if (write_data_size != real_bytes_written) {
                break;
            }

            bytes_written = real_bytes_written;
            result = true;
        } while (false);

        return result;
    }

    bool verify() const {
        return _pipe != INVALID_HANDLE_VALUE;
    }

    void disconnect() {
        if (_pipe != INVALID_HANDLE_VALUE) {
            
            //
            // flush the pipe to allow the client to read the pipe's contents before disconnecting. 
            // then disconnect the pipe, and close the handle to this pipe instance. 
            //

            ::FlushFileBuffers(_pipe);
            ::DisconnectNamedPipe(_pipe);

            ::CloseHandle(_pipe);
        }
    }

    HANDLE& native_object() {
        return _pipe;
    }

private:
    HANDLE _pipe;
    size_t _max_instances;
    
};
} // namespace pipe

해당 클래스는 MSDN을 참조로 만들었습니다.
https://msdn.microsoft.com/ko-kr/library/windows/desktop/aa365588(v=vs.85).aspx

다음엔 클라이언트도 제작하여 서로 통신하는 방법을 보여드리겠습니다.

https://wendys.tistory.com/19







반응형