repo: namedPipes (variosLeitores OverLappedIO)
escritor:
//escritor || servidor //comunicação assincrona (overlapped) #include <windows.h> #include <tchar.h> #include <stdio.h> #include <io.h> #include <fcntl.h> #define PIPE_NAME TEXT("\\\\.\\pipe\\teste") #define N 10 //numero de clientes typedef struct { HANDLE hPipe; OVERLAPPED overlapped; //estrutura overlapped BOOL activo; //se já tem um cliente (pipe) activo ou nao }PipeDados; typedef struct { PipeDados hPipeDados[N]; HANDLE hEvents[N]; int numeroLeitores; //saber em tempo real a quantidade de leitores HANDLE hMutex;//sincronização: acesso sincronizado ao array int terminar; //controlar o fim da thread }ThreadDados; //thread auxiliar, para enviar para um conjunto de handles mensagens DWORD WINAPI TheadMensagens(LPVOID param) { DWORD n; TCHAR buf[256]; ThreadDados* dados = (ThreadDados*)param; int i; do { _tprintf(TEXT("[ESCRITOR] Frase: ")); _fgetts(buf, 256, stdin); buf[_tcslen(buf) - 1] = '\0'; WaitForSingleObject(dados->hMutex, INFINITE); //região critica este ciclo do for for (i = 0; i < dados->numeroLeitores; i++) { //overlapped if(dados->hPipeDados[i].activo){ if (!WriteFile( dados->hPipeDados[i].hPipe, buf, //a string (DWORD)_tcslen(buf) * sizeof(TCHAR), //tamnho que se vai escrever: quantidade de caracteres * bytes que ocupa &n, //qt de informação que foi escrita NULL )) { _tprintf(TEXT("[ERRO] Escrever no pipe! (WriteFile)\n")); exit(-1); } _tprintf(TEXT("[ESCRITOR] Enviei %d bytes ao leitor [%d]... (WriteFile)\n"), n, i); } } ReleaseMutex(dados->hMutex); } while (_tcscmp(buf, TEXT("fim"))); dados->terminar = 1; for(i=0; i<dados->numeroLeitores; i++) { SetEvent(dados->hEvents[i]); } return 0; } int _tmain(int argc, LPTSTR argv[]) { HANDLE hPipe; TCHAR buf[256]; //ou 256 * sizeof(TCHAR) ThreadDados dados; #ifdef UNICODE _setmode(_fileno(stdin), _O_WTEXT); _setmode(_fileno(stdout), _O_WTEXT); _setmode(_fileno(stderr), _O_WTEXT); #endif dados.numeroLeitores = 0; dados.terminar = 0; dados.hMutex = CreateMutex( NULL, FALSE, NULL ); if (dados.hMutex == NULL) { _tprintf(TEXT("[ERRO] CreateMutex! (CreateMutex)")); exit(-1); } HANDLE hThreadMain; hThreadMain = CreateThread(NULL, 0, TheadMensagens, &dados, 0, NULL); if (hThreadMain == NULL) { _tprintf(TEXT("[ERRO] CreateThread! (CreateThread)")); exit(-1); } while (dados.terminar == 0) { _tprintf(TEXT("[ESCRITOR] Criar uma cópia do pipe '%s' ... (CreateNamedPipe)\n"), PIPE_NAME); hPipe = CreateNamedPipe( PIPE_NAME, //nome PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, //modo de abertura do pipe: PIPE_ACCESS_OUTBOUND, o escritor/servidor envia para o cliente!! PIPE_ACCESS_INBOUND, se receber informacoes do cliente e pode ser duplex PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, //modo do funcionamento do pipe. O PIPE_WAIT pipe bloqueante e é tratado como mensagem usando o _MESSAGE N, //numero maximo de instancias sizeof(buf), // tamnho do buffer de entrada sizeof(buf), // tamnho do buffer de saida 1000, // default timeout, tempo de espera de um cliente NULL //atributos de segurança ); 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( //bloqueante, espera que alguém se ligue hPipe, //namepiped NULL // overlaped )) { //devolve 0 se correr mal _tprintf(TEXT("[ERRO] Ligação ao leitor! (ConnectNamedPipe\n")); exit(-1); } //novos clientes, e reigão critica WaitForSingleObject(dados.hMutex, INFINITE); dados.hPipeDados[dados.numeroLeitores].hPipe = hPipe; //dados.hPipeDados[dados.numeroLeitores].overlapped; dados.numeroLeitores++; ReleaseMutex(dados.hMutex); } //esperar que a thread termine WaitForSingleObject(hThreadMain, INFINITE); for (int i = 0; i < dados.numeroLeitores; i++) { _tprintf(TEXT("[ESCRITOR] Desligar o pipe (DisconnectNamedPipe)\n")); if (!DisconnectNamedPipe(dados.hEvents[i])) { _tprintf(TEXT("[ERRO] Desligar o pipe! (DisconnectNamedPipe)")); exit(-1); } } // Sleep(2000); // CloseHandle(hPipe); return 0; }
leitor:
//leitor || cliente //comunicação assincrona (overlapped) #include <windows.h> #include <tchar.h> #include <stdio.h> #include <io.h> #include <fcntl.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); _setmode(_fileno(stderr), _O_WTEXT); #endif _tprintf(TEXT("[LEITOR] Esperar pelo pipe '%s' (WaitNamedPipe)\n"), PIPE_NAME); if (!WaitNamedPipe( PIPE_NAME, //string do nome do namedPipe NMPWAIT_WAIT_FOREVER //timeout para sempre NMPWAIT_WAIT_FOREVER, ou espera os 1000 NMPWAIT_USE_DEFAULT_WAIT )) { _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, //nome do namedPipe GENERIC_READ, //as permissões, ver PIPE_ACCESS_OUTBOUND, mas se fosse PIPE_ACCESS_INBOUND seria GENERIC_WRITE 0, //shared mode NULL, // security OPEN_EXISTING, //flags de criação, é sempre OPEN_EXISTING FILE_ATTRIBUTE_NORMAL, //flags NULL // template nao usamos ); 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( //cliente é só de leitura hPipe, // handle do pipe buf, //ponteiro onde escreve a informação lida sizeof(buf), //qt máxima de informações que cabem, 256 caracteres &n, //ponteiro, a quantidade de bytes que foram escrito NULL //overlaped, nao interessa ); buf[n / sizeof(TCHAR)] = '\0'; //tamanho de caracteres, 1 byte se for ascii ou de 2 bytes 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; }
Comunicação assincrona (overlapped)
_operações que normamente bloqueiam até completarem (read, write) podem ser completadas em background pelo SO
_isto consegue-se passando um ponteiro não nulo para uma estrutura do tipo OVERLAPPED
_se na estrutura for passado um handle para um evento, esse evento é assinalado quando a operação for completada pelo SO
processo, faz:
pedido de operação overlapped (não bloqueante)
e operação feita em background pelo SO, faz:
evento (opcional)
a estrutura do tipo overlapped deve ser inicializada a zero
a estrutura pode levar o handle de evento, depois dele ser criado
OVERLAPPED overlap;
ZeroMemory(&overlap, sizeof(overlap));
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //criar evento
overlap.hEvent = hEvent;
ConnectNamedPipe(hPipe, &overlap);
É possivel determinar o resultado de uma operação assincrona com GetOverlappedResult
BOOL GetOverlappedResult(
HANDLE hFile, //ponteiro para pipe, ficheiro,
LPOVERLAPPED lpOverLapped, // ponteiro para estrutura do tipo OVERLAPPED
LPWORD lpNumberOfBytesTransferred, // variavel para receber n de bytes
BOOl bWait //TRUE = espera que operação termine
);
0 thoughts on “repo: namedPipes (variosLeitores OverLappedIO)”