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;
}
Tags : ,

0 thoughts on “repo: namedPipes (variosLeitores)”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.