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)”