repo: namedPipes (variosLeitores OverLappedIO) outra versão

escritor:

#include <tchar.h>
#include <math.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <windows.h>

#define PIPE_NAME TEXT("\\\\.\\pipe\\teste")
#define N 3

// estrutura do named pipe
typedef struct {
	HANDLE hPipe; // handle do pipe
	OVERLAPPED overlap;
	BOOL activo; //representa se a instancia do named pipe esta ou nao ativa, se ja tem um cliente ou nao

} PipeDados;

typedef struct {
	PipeDados hPipes[N];
	HANDLE hEvents[N];
	HANDLE hMutex;
	int terminar;
}ThreadDados;

//envia mensagem para todos os leitores que estão disponiveis
DWORD WINAPI ThreadMensagens(LPVOID param) {
	ThreadDados* dados = (ThreadDados*)param;
	TCHAR buf[256];
	DWORD n;
	int i;
	BOOL ret;

	do {
		_tprintf(TEXT("[ESCRITOR] Frase: "));
		_fgetts(buf, 256, stdin);
		buf[_tcslen(buf) - 1] = '\0';
		
		for (i = 0; i < N; i++) {
			// este named pipe está ativo? se sim vou escrever nele
			if (dados->hPipes[i].activo == TRUE) {
				if (!WriteFile(dados->hPipes[i].hPipe, buf, (DWORD)_tcslen(buf) * sizeof(TCHAR), &n, NULL)) {
					_tprintf(TEXT("[ERRO] Escrever no pipe! (WriteFile)\n"));
				}
				WaitForSingleObject(dados->hMutex, INFINITE);
				ret=ReadFile(dados->hPipes[i].hPipe, buf, sizeof(TCHAR), &n, NULL);
				ReleaseMutex(dados->hMutex);
				//termina corretamente a string
				buf[n / sizeof(TCHAR)] = '\0';
				_tprintf(TEXT("[ESCRITOR] Recebi %d bytes [%s]... \n"), n, buf);
			}
			//libertamos o mutex

		}
		

		_tprintf(TEXT("[ESCRITOR] Enviei %d bytes ao leitor [%d]... (WriteFile)\n"), n, i);

	} while (_tcscmp(buf, TEXT("fim")));
	dados->terminar = 1;

	//vou assinalar todos os eventos para que nao fique bloqueado na main
	for (i = 0; i < N; i++)
		SetEvent(dados->hEvents[i]);

	return 0;
}

int _tmain(int argc, LPTSTR argv[]) {

	HANDLE hPipe, hThread, hEventTemp;
	ThreadDados dados;
	int i, numClientes = 0;
	DWORD offset, nBytes;

#ifdef UNICODE
	_setmode(_fileno(stdin), _O_WTEXT);
	_setmode(_fileno(stdout), _O_WTEXT);
#endif

	dados.terminar = 0;
	dados.hMutex = CreateMutex(NULL, FALSE, NULL); //Criação do mutex

	if (dados.hMutex == NULL) {
		_tprintf(TEXT("[Erro] ao criar mutex!\n"));
		return -1;
	}


	for (i = 0; i < N; i++) {

		// aqui passamos a constante FILE_FLAG_OVERLAPPED para o named pipe aceitar comunicações assincronas
		hPipe = CreateNamedPipe(PIPE_NAME, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
			PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE,
			N,
			256 * sizeof(TCHAR),
			256 * sizeof(TCHAR),
			1000,
			NULL);

		if (hPipe == INVALID_HANDLE_VALUE) {
			_tprintf(TEXT("[ERRO] Criar Named Pipe! (CreateNamedPipe)"));
			exit(-1);
		}

		// criar evento que vai ser associado à esturtura overlaped
		// os eventos aqui tem de ter sempre reset manual e nao automático porque temos de delegar essas responsabilidades ao sistema operativo
		hEventTemp = CreateEvent(NULL, TRUE, FALSE, NULL);

		if (hEventTemp == NULL) {
			_tprintf(TEXT("[ERRO] ao criar evento\n"));
			return -1;
		}

		dados.hPipes[i].hPipe = hPipe;
		dados.hPipes[i].activo = FALSE;
		//temos de garantir que a estrutura overlap está limpa
		ZeroMemory(&dados.hPipes[i].overlap, sizeof(dados.hPipes[i].overlap));
		//preenchemos agora o evento
		dados.hPipes[i].overlap.hEvent = hEventTemp;
		dados.hEvents[i] = hEventTemp;

		_tprintf(TEXT("[ESCRITOR] Esperar ligação de um leitor... (ConnectNamedPipe)\n"));

		// aqui passamos um ponteiro para a estrutura overlap
		ConnectNamedPipe(hPipe, &dados.hPipes[i].overlap);
	}

	//criacao da thread
	hThread = CreateThread(NULL, 0, ThreadMensagens, &dados, 0, NULL);
	if (hThread == NULL) {
		_tprintf(TEXT("[Erro] ao criar thread!\n"));
		return -1;
	}

	while (!dados.terminar && numClientes < N) {
		//permite estar bloqueado , à espera que 1 evento do array de enventos seja assinalado
		offset = WaitForMultipleObjects(N, dados.hEvents, FALSE, INFINITE);
		i = offset - WAIT_OBJECT_0; // devolve o indice da instancia do named pipe que está ativa, aqui sabemos em que indice o cliente se ligou

		// se é um indice válido ...
		if (i >= 0 && i < N) {

			_tprintf(TEXT("[ESCRITOR] Leitor %d chegou\n"), i);
			if (GetOverlappedResult(dados.hPipes[i].hPipe, &dados.hPipes[i].overlap, &nBytes, FALSE)) {
				// se entrarmos aqui significa que a funcao correu tudo bem
				// fazemos reset do evento porque queremos que o WaitForMultipleObject desbloqueio com base noutro evento e nao neste
				ResetEvent(dados.hEvents[i]);

				//vamos esperar que o mutex esteja livre
				WaitForSingleObject(dados.hMutex, INFINITE);
				dados.hPipes[i].activo = TRUE; // dizemos que esta instancia do named pipe está ativa
				ReleaseMutex(dados.hMutex);

				numClientes++;
			}
		}
	}


	//esperar que a thread termine
	WaitForSingleObject(hThread, INFINITE);

	//desligamos todos os clientes que se ligaram
	for (int i = 0; i < N; i++) {
		_tprintf(TEXT("[ESCRITOR] Desligar o pipe (DisconnectNamedPipe)\n"));

		//desliga todas as instancias de named pipes
		if (!DisconnectNamedPipe(dados.hPipes[i].hPipe)) {
			_tprintf(TEXT("[ERRO] Desligar o pipe! (DisconnectNamedPipe)"));
			exit(-1);
		}
	}


	exit(0);
}

leitor:

#include <tchar.h>
#include <math.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <windows.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);

	//espera que exista um named pipe para ler do mesmo
	//bloqueia aqui
	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"));

	//ligamo-nos ao named pipe que ja existe nesta altura
	//1º nome do named pipe, 2ºpermissoes (têm de ser iguais ao CreateNamedPipe do servidor), 3ºshared mode 0 aqui,
	//4º security atributes, 5ºflags de criação OPEN_EXISTING, 6º o default é FILE_ATTRIBUTE_NORMAL e o 7º é o template é NULL
	hPipe = CreateFile(PIPE_NAME, PIPE_ACCESS_DUPLEX, 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) {
		//le as mensagens enviadas pelo servidor
		ret = ReadFile(hPipe, buf, sizeof(TCHAR), &n, NULL);
		 
		//termina corretamente a string
		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);

		for (int i = 0; i < (int)n; i++) {
			if (!WriteFile(hPipe, buf, (DWORD)_tcslen(buf) * sizeof(TCHAR), &n, NULL)) {
				_tprintf(TEXT("[ERRO] escrever no pipe\n"));
			}
			else {
				_tprintf(TEXT("[LEITOR] enviei %d butes ao escritor\n"), n);
			}
		}

	}
	CloseHandle(hPipe);
	Sleep(200);

	return 0;
}
Tags : ,

0 thoughts on “repo: namedPipes (variosLeitores OverLappedIO) outra versão”

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.