repo: namedPipes (variosLeitores)
escritor:
//escritor || servidor //(thread secundária para partilhar por todos os leitores em simultaneos) //(mais do que um leitor ao mesmo tempo) //(o acesso à informação de exclusão mutua) //array com handles dos named pipes #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 hPipes[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++) { if (!WriteFile( dados->hPipes[i], 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; //extra e depois do dados->terminar = 1; //simular a entrada de um novo cliente para desbloquear o ConnectNamedPipe no _main CreateFile(PIPE_NAME, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 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, //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")); //mas o fim nao funciona: //1ª solução correta para desbloquear isto //2ª solução simular que surge um cliente novo para desbloquear este ConnectNamedPipe quando é escrito fim 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.hPipes[dados.numeroLeitores] = hPipe; 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.hPipes[i])) { _tprintf(TEXT("[ERRO] Desligar o pipe! (DisconnectNamedPipe)")); exit(-1); } } // Sleep(2000); // CloseHandle(hPipe); return 0; }
leitor:
//leitor || cliente #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; }
0 thoughts on “repo: namedPipes (variosLeitores)”