Листинг 2. Программа Talk
#include <windows.h>
#include <iostream.h>
#include <string.h>
#include <stdio.h> // sprintf
BOOL server=FALSE;
HANDLE OpenTalkPipe(char *host)
{
HANDLE rv;
if (!server)
{
char fn[1024];
sprintf(fn,"\\\\%s\\pipe\\talkpipe_awc",host);
cerr<<"Открываю канал: "<<fn<<"\n";
rv=CreateFile(fn, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
}
else
{
// программа в режиме сервера
rv=CreateNamedPipe("\\\\.\\pipe\\talkpipe_awc",PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED,PIPE_TYPE_BYTE|PIPE_READMODE_BYTE,1,1024,1024,1000,NULL);
}
return rv;
}
void main(int argc, char *argv[])
{
if (argc==1) server=TRUE;
HANDLE pipe=OpenTalkPipe(server?".":argv[1]);
HANDLE console=GetStdHandle(STD_INPUT_HANDLE);
HANDLE pipeevent=CreateEvent(NULL, TRUE, FALSE, NULL);
OVERLAPPED over;
char pipebuf;
DWORD inlen;
DWORD err;
if (pipe==INVALID_HANDLE_VALUE)
{
err=GetLastError();
cout<<"Ошибка при открытии канала ("<<err<<")\n";
exit(9);
}
over.Internal=over.InternalHigh=over.Offset=over.OffsetHigh=0;
over.hEvent=pipeevent;
if (!SetConsoleMode(console,0))
{
cerr<<"Error: не могу войти в режим консоли\n"<<GetLastError();
exit(4);
}
cout<<"Ожидание соединения\n";
cout.flush();
//Чтение канала
do {
while (ReadFile(pipe,&pipebuf,1,&inlen,&over)) cout<<pipebuf;
err=GetLastError();
} while (err==ERROR_PIPE_LISTENING); // ожидание для клиента
cerr<<"Соединение установлено(^C для разрыва связи)\n";
if (err!=ERROR_IO_PENDING)
{
cerr<<"Ошибка чтения канала ("<<err<<")\n";
exit(3);
}
// Вход в режим ожидания
HANDLE waits[2];
DWORD obj;
waits[0]=pipeevent;
waits[1]=console;
while (1)
{
obj=WaitForMultipleObjects(2,(void **)&waits,FALSE,INFINITE);
// если ожидание прервано консолью, принимаем данные и шлем их в канал
if (obj==WAIT_OBJECT_0+1)
{
char inbuf; // только ANSI коды
OVERLAPPED dummy;
INPUT_RECORD irec;
dummy.hEvent=NULL;
dummy.Offset=dummy.OffsetHigh=dummy.Internal=dummy.InternalHigh=0;
DWORD inlen;
// Использование ReadConsole не сбрасывает сигнального состояния консоли
ReadConsoleInput(console,&irec,1,&inlen);
if (irec.EventType==KEY_EVENT&&irec.Event.KeyEvent.bKeyDown&&
irec.Event.KeyEvent.uChar.AsciiChar!='\0')
{
inbuf=irec.Event.KeyEvent.uChar.AsciiChar;
if (inbuf=='\003')
{
// Завершение
CloseHandle(pipe);
CloseHandle(pipeevent);
exit(0);
}
WriteFile(pipe,&inbuf,1,&inlen,&dummy);
// Эхо
cout<<((inbuf=='\r')?'\n':inbuf);
cout.flush();
// Ожидаем завершение записи
if (!GetOverlappedResult(pipe,&dummy,&inlen,TRUE))
cout<<"Неизвестная ошибка записи в канал!\n";
}
}
// если ожидание завершено, вывести символ на консоль
if (obj==WAIT_OBJECT_0)
{
DWORD len;
// Получить результат, несмотря на то, что мы о нем уже знаем
if (!GetOverlappedResult(pipe,&over,&len,TRUE))
{
cout<<"!Неизвестная ошибка консоли!\n";
exit(3);
}
do
{
if (pipebuf=='\r') cout<<'\n'; else cout<<pipebuf;
} while (ReadFile(pipe,&pipebuf,1,&inlen,&over));
DWORD err=GetLastError();
if (err!=ERROR_IO_PENDING)
{
cerr<<"Ошибка чтения канала\n";
exit(3);
}
cout.flush();
}
}
}
Клиент и сервер открывают канал для перекрывающегося ввода/вывода. Ввод с консоли осуществляется традиционным методом, так как при появлении на консоли данных для ввода дескриптор консоли автоматически переходит в сигнальное состояние, и программа может среагировать на это, даже если она не использует для ввода с консоли перекрывающегося ввода/вывода.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.