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;
}
0 thoughts on “repo: namedPipes (variosLeitores OverLappedIO) outra versão”