问题描述
- windows 重叠IO 命名管道程序疑问?
-
我写了一个命名管道通信例子,但是现在有两个疑问?
疑问1 : 为什么我的程序只能由客户端向服务器发送数据,服务端不能向客户端发送数据呢?服务端显示发送成功,但是客户端相应的可读事件不能被触发。
疑问2 : 偶尔出现客户端向服务器发送数据的时候 前一两个包丢失。服务端代码:
#include "stdafx.h" #include <windows.h> #include <stdio.h> #include <tchar.h> #include <strsafe.h> #define CONNECTING_STATE 3 #define READING_STATE 1 #define WRITING_STATE 2 #define INSTANCES 1 #define PIPE_TIMEOUT 5000 #define BUFSIZE 4096 typedef struct { OVERLAPPED oOverlap; HANDLE hPipeInst; } PIPEINST, *LPPIPEINST; VOID DisconnectAndReconnect(DWORD); BOOL ConnectToNewClient(HANDLE, LPOVERLAPPED); bool PostRecvRequest(LPPIPEINST hInst) { if (NULL == hInst) return false; char buf[1] = {0}; DWORD dwBytesReaded = 0; if (!ReadFile(hInst->hPipeInst, buf, 1, &dwBytesReaded, &hInst->oOverlap)) { DWORD err = GetLastError(); if (err != ERROR_IO_PENDING) { printf("client ReadFile error : %d n", err); return false; } } return true; } bool IsNamedPipeCanRecv(LPPIPEINST hInst) { if (NULL == hInst) return false; if (WAIT_OBJECT_0 ==WaitForSingleObject(hInst->oOverlap.hEvent, INFINITE)) { return true; } ResetEvent(hInst->oOverlap.hEvent); return false; } DWORD WINAPI RecvThread(LPVOID param) { LPPIPEINST hInst = (LPPIPEINST) param; if (hInst) { while(1) { if (IsNamedPipeCanRecv(hInst)) { char buf[1024] = {0}; DWORD dwBytesReaded = 0; ReadFile(hInst->hPipeInst, buf, 1024, &dwBytesReaded, NULL); printf("Server recv : %sn", buf); } PostRecvRequest(hInst); } } return 0; } PIPEINST Pipe[INSTANCES]; HANDLE hEvents[INSTANCES]; int _tmain(int argc, _TCHAR* argv[]) { LPTSTR lpszPipename = TEXT("\\.\pipe\mynamedpipe"); for (int i = 0; i < INSTANCES; i++) { // Create an event object for this instance. hEvents[i] = CreateEvent( NULL, // default security attribute TRUE, // manual-reset event TRUE, // initial state = signaled NULL); // unnamed event object if (hEvents[i] == NULL) { printf("CreateEvent failed with %d.n", GetLastError()); return 0; } Pipe[i].oOverlap.hEvent = hEvents[i]; Pipe[i].hPipeInst = CreateNamedPipe( lpszPipename, // pipe name PIPE_ACCESS_DUPLEX | // read/write access FILE_FLAG_OVERLAPPED, // overlapped mode PIPE_TYPE_MESSAGE | // message-type pipe PIPE_READMODE_MESSAGE | // message-read mode PIPE_WAIT, // blocking mode INSTANCES, // number of instances BUFSIZE*sizeof(TCHAR), // output buffer size BUFSIZE*sizeof(TCHAR), // input buffer size PIPE_TIMEOUT, // client time-out NULL); // default security attributes if (Pipe[i].hPipeInst == INVALID_HANDLE_VALUE) { printf("CreateNamedPipe failed with %d.n", GetLastError()); return 0; } ConnectToNewClient( Pipe[i].hPipeInst, &Pipe[i].oOverlap); } HANDLE hThread = CreateThread(0, 0, RecvThread, &Pipe[0], 0, 0); while (1) { char buf[1024]; scanf("%s", buf); DWORD dw; BOOL b = WriteFile(Pipe[0].hPipeInst, buf, strlen(buf), &dw, &Pipe[0].oOverlap); printf("send(%d:%d) : %sn", dw, b, buf); } return 0; } VOID DisconnectAndReconnect(DWORD i) { // Disconnect the pipe instance. if (! DisconnectNamedPipe(Pipe[i].hPipeInst) ) { printf("DisconnectNamedPipe failed with %d.n", GetLastError()); } // Call a subroutine to connect to the new client. ConnectToNewClient( Pipe[i].hPipeInst, &Pipe[i].oOverlap); } BOOL ConnectToNewClient(HANDLE hPipe, LPOVERLAPPED lpo) { BOOL fConnected, fPendingIO = FALSE; // Start an overlapped connection for this pipe instance. fConnected = ConnectNamedPipe(hPipe, lpo); // Overlapped ConnectNamedPipe should return zero. if (fConnected) { printf("ConnectNamedPipe failed with %d.n", GetLastError()); return 0; } switch (GetLastError()) { // The overlapped connection in progress. case ERROR_IO_PENDING: fPendingIO = TRUE; break; // Client is already connected, so signal an event. case ERROR_PIPE_CONNECTED: if (SetEvent(lpo->hEvent)) break; // If an error occurs during the connect operation... default: { printf("ConnectNamedPipe failed with %d.n", GetLastError()); return 0; } } return fPendingIO; }
客户端代码
#include "stdafx.h" #include <windows.h> #include <stdio.h> #include <conio.h> #include <tchar.h> #define BUFSIZE 512 typedef struct { OVERLAPPED oOverlap; HANDLE hPipeInst; } PIPEINST, *LPPIPEINST; bool PostRecvRequest(LPPIPEINST hInst) { if (NULL == hInst) return false; char buf[1] = {0}; DWORD dwBytesReaded = 0; if (!ReadFile(hInst->hPipeInst, buf, 1, &dwBytesReaded, &hInst->oOverlap)) { DWORD err = GetLastError(); if (err != ERROR_IO_PENDING) { // 109 管道已结束 printf("client ReadFile error : %d n", err); return false; } } return true; } bool IsNamedPipeCanRecv(LPPIPEINST hInst) { if (NULL == hInst) return false; if (WAIT_OBJECT_0 ==WaitForSingleObject(hInst->oOverlap.hEvent, INFINITE)) { return true; } ResetEvent(hInst->oOverlap.hEvent); return false; } DWORD WINAPI RecvThread(LPVOID param) { LPPIPEINST hInst = (LPPIPEINST) param; if (hInst) { while(1) { if (IsNamedPipeCanRecv(hInst)) { char buf[1024] = {0}; DWORD dwBytesReaded = 0; ReadFile(hInst->hPipeInst, buf, 1024, &dwBytesReaded, NULL); printf("Client recv : %sn", buf); } PostRecvRequest(hInst); } } return 0; } int _tmain(int argc, _TCHAR* argv[]) { PIPEINST Pipe; Pipe.oOverlap.hEvent = CreateEvent( NULL, // default security attribute TRUE, // manual-reset event FALSE, // initial state = signaled NULL); // unnamed event object LPTSTR lpvMessage=TEXT("Default message from client."); BOOL fSuccess = FALSE; DWORD dwMode; LPTSTR lpszPipename = TEXT("\\.\pipe\mynamedpipe"); if( argc > 1 ) lpvMessage = argv[1]; // Try to open a named pipe; wait for it, if necessary. while (1) { Pipe.hPipeInst = CreateFile( lpszPipename, // pipe name GENERIC_READ | GENERIC_WRITE, // read and write access 0, // no sharing NULL, // default security attributes OPEN_EXISTING, // opens existing pipe FILE_FLAG_OVERLAPPED, // default attributes NULL); // no template file // Break if the pipe handle is valid. if ( Pipe.hPipeInst != INVALID_HANDLE_VALUE) break; // Exit if an error other than ERROR_PIPE_BUSY occurs. if (GetLastError() != ERROR_PIPE_BUSY) { _tprintf( TEXT("Could not open pipe. GLE=%dn"), GetLastError() ); return -1; } // All pipe instances are busy, so wait for 20 seconds. if ( ! WaitNamedPipe(lpszPipename, 20000)) { printf("Could not open pipe: 20 second wait timed out."); return -1; } } // The pipe connected; change to message-read mode. dwMode = PIPE_READMODE_MESSAGE | PIPE_WAIT; fSuccess = SetNamedPipeHandleState( Pipe.hPipeInst, // pipe handle &dwMode, // new pipe mode NULL, // don't set maximum bytes NULL); // don't set maximum time if ( ! fSuccess) { _tprintf( TEXT("SetNamedPipeHandleState failed. GLE=%dn"), GetLastError() ); return -1; } // Send a message to the pipe server. PostRecvRequest(&Pipe); HANDLE hThread = CreateThread(0, 0, RecvThread, &Pipe, 0, 0); while (1) { char buf[1024]; scanf("%s", buf); DWORD dw; WriteFile(Pipe.hPipeInst, buf, strlen(buf), &dw, NULL); printf("send(%d) : %sn", dw, buf); } return 0; }
解决方案
你客户端也要像服务端那样也创建一个对应事件的管道,然后让服务端反向给你数据。
解决方案二:
管道是单向的。不然要设置两个双向的管道
解决方案三:
不是单向的啊,只要我不等待事件触发就可以正常接收,现在就是客户端事件没有被置信
时间: 2024-12-26 21:23:12