repo: namedPipes (variosLeitores OverLappedIO)
escritor:
//escritor || servidor
//comunicação assincrona (overlapped)
#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 hPipe;
OVERLAPPED overlapped; //estrutura overlapped
BOOL activo; //se já tem um cliente (pipe) activo ou nao
}PipeDados;
typedef struct {
PipeDados hPipeDados[N];
HANDLE hEvents[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++) {
//overlapped
if(dados->hPipeDados[i].activo){
if (!WriteFile(
dados->hPipeDados[i].hPipe,
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;
for(i=0; i<dados->numeroLeitores; i++)
{
SetEvent(dados->hEvents[i]);
}
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 | FILE_FLAG_OVERLAPPED, //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"));
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.hPipeDados[dados.numeroLeitores].hPipe = hPipe;
//dados.hPipeDados[dados.numeroLeitores].overlapped;
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.hEvents[i])) {
_tprintf(TEXT("[ERRO] Desligar o pipe! (DisconnectNamedPipe)"));
exit(-1);
}
}
// Sleep(2000);
// CloseHandle(hPipe);
return 0;
}
leitor:
//leitor || cliente
//comunicação assincrona (overlapped)
#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;
}
Comunicação assincrona (overlapped)
_operações que normamente bloqueiam até completarem (read, write) podem ser completadas em background pelo SO
_isto consegue-se passando um ponteiro não nulo para uma estrutura do tipo OVERLAPPED
_se na estrutura for passado um handle para um evento, esse evento é assinalado quando a operação for completada pelo SO
processo, faz:
pedido de operação overlapped (não bloqueante)
e operação feita em background pelo SO, faz:
evento (opcional)
a estrutura do tipo overlapped deve ser inicializada a zero
a estrutura pode levar o handle de evento, depois dele ser criado
OVERLAPPED overlap;
ZeroMemory(&overlap, sizeof(overlap));
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //criar evento
overlap.hEvent = hEvent;
ConnectNamedPipe(hPipe, &overlap);
É possivel determinar o resultado de uma operação assincrona com GetOverlappedResult
BOOL GetOverlappedResult(
HANDLE hFile, //ponteiro para pipe, ficheiro,
LPOVERLAPPED lpOverLapped, // ponteiro para estrutura do tipo OVERLAPPED
LPWORD lpNumberOfBytesTransferred, // variavel para receber n de bytes
BOOl bWait //TRUE = espera que operação termine
);
0 thoughts on “repo: namedPipes (variosLeitores OverLappedIO)”