Sessão 1/2 – Named Pipes
Interprocessos (processo a falar uns com os outros):
Memoria partilhada
Named pipes
Threads do mesmo processo:
espaço de endereçamento do processo
Named pipes:
paradigma cliente <–> servidor
Um pipe com múltiplas instâncias, para resolver o problema de cinco clientes e um servidor
Nos namedPipes permitem comunicação bidirecional (se tiverem permissões de escrita e leitura para o cliente e servidor, mas não pode ser em simultâneo)
Servidor:
Tem uma thread para cada cliente
1º CreateNamedPipe
2º ConnectNamedPipe
3º Thread Secundária para atender os clientes
4º (fechar) FlushFileBuffers
5º (fechar) DisconnecNamedPipes
6º (fechar) CloseHandle
Cliente:
1º (ligar) CreateFile ou CallNamedPipe
2º (aguarda pela instância) WaitNamedPipe
3º SetNamedPipeHandleState
4º fechar os handles do processo
exemplos base
//escritor.c #include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #include <time.h> #define PIPE_NAME TEXT("\\\\.\\pipe\\teste") int _tmain(int argc, LPTSTR argv[]) { DWORD n; HANDLE hPipe; TCHAR buf[256]; #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); #endif _tprintf(TEXT("[ESCRITOR] Criar uma cópia do pipe '%s' ... (CreateNamedPipe)\n"), PIPE_NAME); hPipe = CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_OUTBOUND, PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 1, sizeof(buf), sizeof(buf), 1000, NULL); if (hPipe == INVALID_HANDLE_VALUE) { _tprintf(TEXT("[ERRO] Criar Named Pipe! (CreateNamedPipe)")); exit(-1); } while (1) { _tprintf(TEXT("[ESCRITOR] Esperar ligação de um leitor... (ConnectNamedPipe)\n")); if (!ConnectNamedPipe(hPipe, NULL)) { _tprintf(TEXT("[ERRO] Ligação ao leitor! (ConnectNamedPipe\n")); exit(-1); } do { _tprintf(TEXT("[ESCRITOR] Frase: ")); _fgetts(buf, 256, stdin); buf[_tcslen(buf) - 1] = '\0'; if (!WriteFile(hPipe, buf, _tcslen(buf) * sizeof(TCHAR), &n, NULL)) { _tprintf(TEXT("[ERRO] Escrever no pipe! (WriteFile)\n")); exit(-1); } _tprintf(TEXT("[ESCRITOR] Enviei %d bytes ao leitor... (WriteFile)\n"), n); } while (_tcscmp(buf, TEXT("fim"))); _tprintf(TEXT("[ESCRITOR] Desligar o pipe (DisconnectNamedPipe)\n")); if (!DisconnectNamedPipe(hPipe)) { _tprintf(TEXT("[ERRO] Desligar o pipe! (DisconnectNamedPipe)")); exit(-1); } } Sleep(2000); CloseHandle(hPipe); exit(0); }
//leitor.c #include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #include <time.h> // ... #define PIPE_NAME TEXT("\\\\.\\pipe\\teste") int _tmain(int argc, LPTSTR argv[]) { TCHAR buf[256]; HANDLE hPipe; int i = 0; BOOL ret; DWORD n; #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); #endif _tprintf(TEXT("[LEITOR] Esperar pelo pipe '%s' (WaitNamedPipe)\n"), PIPE_NAME); if (!WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER)) { _tprintf(TEXT("[ERRO] Ligar ao pipe '%s'! (WaitNamedPipe)\n"), PIPE_NAME); exit(-1); } _tprintf(TEXT("[LEITOR] Ligação ao pipe do escritor... (CreateFile)\n")); hPipe = CreateFile(PIPE_NAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hPipe == NULL) { _tprintf(TEXT("[ERRO] Ligar ao pipe '%s'! (CreateFile)\n"), PIPE_NAME); exit(-1); } _tprintf(TEXT("[LEITOR] Liguei-me...\n")); while (1) { ret = ReadFile(hPipe, buf, sizeof(buf), &n, NULL); buf[n / sizeof(TCHAR)] = '\0'; if (!ret || !n) { _tprintf(TEXT("[LEITOR] %d %d... (ReadFile)\n"), ret, n); break; } _tprintf(TEXT("[LEITOR] Recebi %d bytes: '%s'... (ReadFile)\n"), n, buf); } CloseHandle(hPipe); Sleep(200); return 0; }
Nova versão com comnetários:
//escritor.c #include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #include <time.h> #define PIPE_NAME TEXT("\\\\.\\pipe\\teste") int _tmain(int argc, LPTSTR argv[]) { DWORD n; HANDLE hPipe; TCHAR buf[256]; #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); #endif _tprintf(TEXT("[ESCRITOR] Criar uma cópia do pipe '%s' ... (CreateNamedPipe)\n"), PIPE_NAME); hPipe = CreateNamedPipe( PIPE_NAME, //nome pipe PIPE_ACCESS_OUTBOUND, //modo de abertura do pipe só o servidor escreve PIPE_WAIT | // bloqueante: bloqueio ate escrever PIPE_TYPE_MESSAGE | // organização da informação: agrupa bytes em mensagens na escrita PIPE_READMODE_MESSAGE, // organização da informação: agrupa bytes em mensagens na leitura 1, // numero maximo de instancias sizeof(buf), // tamanho da mensagem sizeof(buf), // tamanho da mensagem 1000, // tempo de espera do cliente para usar no: waitNamedPipe (cliente) NULL // ); if (hPipe == INVALID_HANDLE_VALUE) { _tprintf(TEXT("[ERRO] Criar Named Pipe! (CreateNamedPipe)")); exit(-1); } while (1) { _tprintf(TEXT("[ESCRITOR] Esperar ligação de um leitor... (ConnectNamedPipe)\n")); if (!ConnectNamedPipe(hPipe, NULL)) { //operação bloqueante até que aja um cliente _tprintf(TEXT("[ERRO] Ligação ao leitor! (ConnectNamedPipe\n")); exit(-1); } do { _tprintf(TEXT("[ESCRITOR] Frase: ")); _fgetts(buf, 256, stdin); buf[_tcslen(buf) - 1] = '\0'; if (!WriteFile(hPipe, buf, _tcslen(buf) * sizeof(TCHAR), &n, NULL)) { _tprintf(TEXT("[ERRO] Escrever no pipe! (WriteFile)\n")); exit(-1); } _tprintf(TEXT("[ESCRITOR] Enviei %d bytes ao leitor... (WriteFile)\n"), n); } while (_tcscmp(buf, TEXT("fim"))); _tprintf(TEXT("[ESCRITOR] Desligar o pipe (DisconnectNamedPipe)\n")); if (!DisconnectNamedPipe(hPipe)) { _tprintf(TEXT("[ERRO] Desligar o pipe! (DisconnectNamedPipe)")); exit(-1); } } Sleep(2000); CloseHandle(hPipe); exit(0); }
//leitor.c ou cliente.c #include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #include <time.h> #define PIPE_NAME TEXT("\\\\.\\pipe\\teste") int _tmain(int argc, LPTSTR argv[]) { TCHAR buf[256]; HANDLE hPipe; int i = 0; BOOL ret; DWORD n; #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); #endif _tprintf(TEXT("[LEITOR] Esperar pelo pipe '%s' (WaitNamedPipe)\n"), PIPE_NAME); if (!WaitNamedPipe(PIPE_NAME, NMPWAIT_WAIT_FOREVER)) { //garantir que existe do lado do servidor algo ou definir um tempo ms _tprintf(TEXT("[ERRO] Ligar ao pipe '%s'! (WaitNamedPipe)\n"), PIPE_NAME); exit(-1); } _tprintf(TEXT("[LEITOR] Ligação ao pipe do escritor... (CreateFile)\n")); hPipe = CreateFile( PIPE_NAME, // no do ficheiro, nome do namedPipe GENERIC_READ, // (1) 0, // nao se aplica NULL, // nao interessa OPEN_EXISTING, // sempre OPEN, pois já esta criada FILE_ATTRIBUTE_NORMAL, // por default NULL // nao interessa ); //(1) //permissoes de acordo com o CreateNamedPipe, se no servidor foi PIPE_ACCESS_OUTBOUND então aqui tem que ser GENERIC_READ //permissoes de acordo com o CreateNamedPipe, se no servidor foi PIPE_ACCESS_INBOUND então aqui tem que ser GENERIC_WRITE //permissoes de acordo com o CreateNamedPipe, se no servidor foi PIPE_ACCESS_DUPLEX então aqui tem que ser GENERIC_READ | GENERIC_WRITE if (hPipe == NULL) { _tprintf(TEXT("[ERRO] Ligar ao pipe '%s'! (CreateFile)\n"), PIPE_NAME); exit(-1); } _tprintf(TEXT("[LEITOR] Liguei-me...\n")); while (1) { ret = ReadFile( hPipe, // handle para o pipe buf, // onde vai colocar a informação lida sizeof(buf), // a quantidade máxima que pode ler &n, // escreve o numero de bytes que foi lida, inclui o \0 NULL // overllaped nao estamos a usar ); buf[n / sizeof(TCHAR)] = '\0'; //ler o \0 no fim da string if (!ret || !n) { //quando surge o disconnect por parte do servidor _tprintf(TEXT("[LEITOR] %d %d... (ReadFile)\n"), ret, n); break; } _tprintf(TEXT("[LEITOR] Recebi %d bytes: '%s'... (ReadFile)\n"), n, buf); } CloseHandle(hPipe); Sleep(200); return 0; }
uma versão nova do escritor/servidor para aceitar vários clientes:
//escritor.c 2ª versao #include <Windows.h> #include <tchar.h> #include <math.h> #include <stdio.h> #include <fcntl.h> #include <io.h> #include <time.h> #define PIPE_NAME TEXT("\\\\.\\pipe\\teste") #define PIPE_NMAX_INSTANCIAS 10 typedef struct{ HANDLE hPipesCliente[PIPE_NMAX_INSTANCIAS]; int numeroClientes; HANDLE hMutex; //mutexs acesso int terminar; //controlar o fim da thread } ThreadDados; //a thread DWORD WINAPI ThreadMensagens(LPVOID param) { ThreadDados* dados = (ThreadDados*)param; TCHAR buf[256]; DWORD n; do { _tprintf(TEXT("[ESCRITOR] Frase: ")); _fgetts(buf, 256, stdin); buf[_tcslen(buf) - 1] = '\0'; WaitForSingleObject(dados->hMutex, INFINITE); //região critica.. dados->numeroClientes, dados->hPipesCliente[i] for(int i = 0; i < dados->numeroClientes; i++){ if (!WriteFile(dados->hPipesCliente[i], buf, _tcslen(buf) * sizeof(TCHAR), &n, NULL)) { _tprintf(TEXT("[ERRO] Escrever no pipe! (WriteFile)\n")); exit(-1); } _tprintf(TEXT("[ESCRITOR] Enviei %d bytes ao leitor [%d]... (WriteFile)\n"), n, i); } //fim da região cirtica ReleaseMutex(dados->hMutex); } while (_tcscmp(buf, TEXT("fim"))); //terminar dados->terminar = 1; //i) simular o criar um novo cliente, para o "fim" funcionar CreateFile(PIPE_NAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); return 0; } int _tmain(int argc, LPTSTR argv[]) { HANDLE hPipe; //thread ThreadDados dados; //f) HANDLE hThread; #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); #endif dados.numeroClientes = 0; dados.terminar = 0; //criar mutex dados.hMutex = CreateMutex(NULL, FALSE, NULL); if(dados.hMutex == NULL) { _tprintf(TEXT("[ESCRITOR] Erro a criar o mutex\n")); exit(-1); } //g) hThread = CreateThread(NULL, 0, ThreadMensagens, &dados, 0, NULL); if(hThread == NULL) { _tprintf(TEXT("[ESCRITOR] Erro a criar o CreateThread\n")); exit(-1); } //e) while (!dados.terminar) { _tprintf(TEXT("[ESCRITOR] Criar uma cópia do pipe '%s' ... (CreateNamedPipe)\n"), PIPE_NAME); hPipe = CreateNamedPipe( PIPE_NAME, PIPE_ACCESS_OUTBOUND, PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, PIPE_NMAX_INSTANCIAS, //mais clientes 256 * sizeof(TCHAR), //update ou usar outro TCHAR buf[256]; 256 * sizeof(TCHAR), //update ou usar outro TCHAR buf[256]; 1000, NULL // ); if (hPipe == INVALID_HANDLE_VALUE) { _tprintf(TEXT("[ERRO] Criar Named Pipe! (CreateNamedPipe)")); exit(-1); } _tprintf(TEXT("[ESCRITOR] Esperar ligação de um leitor... (ConnectNamedPipe)\n")); if (!ConnectNamedPipe(hPipe, NULL)) { //operação bloqueante até que aja um cliente _tprintf(TEXT("[ERRO] Ligação ao leitor! (ConnectNamedPipe\n")); exit(-1); } //b) WaitForSingleObject(dados.hMutex, INFINITE); //a) ciclo de aceitação dos novos clientes dados.hPipesCliente[dados.numeroClientes] = hPipe; dados.numeroClientes++; //b) ReleaseMutex(dados.hMutex); } //h) esperar que a thread termine WaitForSingleObject(hThread, INFINITE); //c) encerrar com todos os clientes for (int i = 0; i < dados.numeroClientes; i++) { _tprintf(TEXT("[ESCRITOR] Desligar o pipe (DisconnectNamedPipe)\n")); if (!DisconnectNamedPipe(dados.hPipesCliente[i])) { _tprintf(TEXT("[ERRO] Desligar o pipe! (DisconnectNamedPipe)")); exit(-1); } } exit(0); }
0 thoughts on “Sessão 1/2 – Named Pipes”