Server
~cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
VOID InstanceThread(LPVOID); // 쓰레드 함수
VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD); // 스레드
int xx = 0;
DWORD main(VOID)
{
BOOL fConnected;
DWORD dwThreadId;
HANDLE hPipe, hThread; // 쓰레드 핸들
LPTSTR lpszPipename = "\\.\pipe\mynamedpipe"; // 파이프 이름
// The main loop creates an instance of the named pipe and
// then waits for a client to connect to it. When the client
// connects, a thread is created to handle communications
// with that client, and the loop is repeated.
for (;;)
{
// 쓰래드 함수를 생성한다.
hPipe = CreateNamedPipe(
lpszPipename, // pipe name
PIPE_ACCESS_DUPLEX, // read/write access
PIPE_TYPE_MESSAGE | // message type pipe
PIPE_READMODE_MESSAGE | // message-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
PIPE_TIMEOUT, // client time-out
NULL); // no security attribute
if (hPipe == INVALID_HANDLE_VALUE)
MyErrExit("CreatePipe");
// Wait for the client to connect; if it succeeds, // 클라이언트를 연결을 기다린다.
// the function returns a nonzero value. If the function returns // 접속이 될 경우 0 아닌 값이 리턴 되며
// zero, GetLastError returns ERROR_PIPE_CONNECTED. // 만약 0 값이 리턴이 될 경우 ERROR_PIPE_CONNECTED를 리턴한다.
fConnected = ConnectNamedPipe(hPipe, NULL) ?
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
// 연결이 되서 fConnected값이 TRUE가 되었으므로
if (fConnected)
{
// Create a thread for this client. // 연결된 클라이언트를 위한 쓰레드를 생성시킨다.
hThread = CreateThread(
NULL, // no security attribute
0, // default stack size
(LPTHREAD_START_ROUTINE) InstanceThread, // InstanceThread를 생성시킨다.
(LPVOID) hPipe, // thread parameter // 쓰레드 Parameter로 hPipe 핸들값이 들어간다.
0, // not suspended
&dwThreadId); // returns thread ID
// 쓰레드가 생성이 되면 hThread 값이 NULL 이고 그렇지 않으면 열어 놓은 Handle값을 닫아준다.
if (hThread == NULL)
MyErrExit("CreateThread");
else
CloseHandle(hThread);
}
else
// The client could not connect, so close the pipe.
CloseHandle(hPipe);
}
return 1;
}
VOID InstanceThread(LPVOID lpvParam)
{
CHAR chRequest[BUFSIZE]; // 수신 버퍼
CHAR chReply[BUFSIZE]; // 송신 버퍼
DWORD cbBytesRead, cbReplyBytes, cbWritten;
BOOL fSuccess;
HANDLE hPipe;
// The thread's parameter is a handle to a pipe instance.
hPipe = (HANDLE) lpvParam;
while (1)
{
// Read client requests from the pipe.
// hPipe 핸들에서 chRequst에 BUFSIZE만큼 읽어 들여온다.
fSuccess = ReadFile(
hPipe, // handle to pipe
chRequest, // buffer to receive data
BUFSIZE, // size of buffer
&cbBytesRead, // number of bytes read
NULL); // not overlapped I/O
if (! fSuccess || cbBytesRead == 0)
break;
// Request 에 대한 대답을 chReply 버퍼에 넣어준다.
GetAnswerToRequest(chRequest, chReply, &cbReplyBytes);
// chReply를 대답한다.
// Write the reply to the pipe.
fSuccess = WriteFile(
hPipe, // handle to pipe
chReply, // buffer to write from
cbReplyBytes, // number of bytes to write
&cbWritten, // number of bytes written
NULL); // not overlapped I/O
if (! fSuccess || cbReplyBytes != cbWritten) break;
}
// 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.
// 버퍼의 남은 Data를 Flush 해준다.
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
CloseHandle(hPipe);
}
Client
~cpp
#include <windows.h>
DWORD main(int argc, char *argv[])
{
HANDLE hPipe;
LPVOID lpvMessage;
CHAR chBuf[512];
BOOL fSuccess;
DWORD cbRead, cbWritten, dwMode;
LPTSTR lpszPipename = "\\.\pipe\mynamedpipe";
// Try to open a named pipe; wait for it, if necessary.
while (1)
{
hPipe = CreateFile( // 파일을 연다
lpszPipename, // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // no security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
// Break if the pipe handle is valid.
if (hPipe != INVALID_HANDLE_VALUE)
break;
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (GetLastError() != ERROR_PIPE_BUSY)
MyErrExit("Could not open pipe");
// All pipe instances are busy, so wait for 20 seconds.
if (! WaitNamedPipe(lpszPipename, 20000) )
MyErrExit("Could not open pipe");
} // 파일을 열고 Pipe를 서버에 접속하기 전까지 대기 상태로 만들어둔다.
// The pipe connected; change to message-read mode.
// 파이프가 연결이 되면 파이프를 읽기용으로 바꾼다.
// 여기서 잠깐 PIPE_READMODE_MESSAGE는 읽기용이라고 나와있지만 MSDN에는 이 모드가 새로운 모드로
// 읽기와 쓰기 모두 가능한 모드라고 나와 있다.
// Default는 PIPE_READMODE_DATA 이고 PIPE_READMODE_MESSAGE가 실패할 경우 default로 정해진다.
dwMode = PIPE_READMODE_MESSAGE;
fSuccess = SetNamedPipeHandleState(
hPipe, // pipe handle
&dwMode, // new pipe mode
NULL, // don't set maximum bytes
NULL); // don't set maximum time
if (!fSuccess)
MyErrExit("SetNamedPipeHandleState");
// Send a message to the pipe server.
// 파이프로 메세지를 보낸다.
lpvMessage = (argc > 1) ? argv[1] : "default message";
fSuccess = WriteFile(
hPipe, // pipe handle
lpvMessage, // message
strlen(lpvMessage) + 1, // message length
&cbWritten, // bytes written
NULL); // not overlapped
if (! fSuccess)
MyErrExit("WriteFile");
// 파이프로 부터 메세지를 읽어온다.
do
{
// Read from the pipe.
// 파이프로부터 읽기
fSuccess = ReadFile(
hPipe, // pipe handle
chBuf, // buffer to receive reply
512, // size of buffer
&cbRead, // number of bytes read
NULL); // not overlapped
if (! fSuccess && GetLastError() != ERROR_MORE_DATA)
break;
// Reply from the pipe is written to STDOUT.
// STDOUT로 Reply 쓰기
if (! WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
chBuf, cbRead, &cbWritten, NULL))
{
break;
}
} while (! fSuccess); // repeat loop if ERROR_MORE_DATA
CloseHandle(hPipe);
return 0;
}