lzg13541043726 2015-07-10 07:53 采纳率: 100%
浏览 2357
已采纳

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 : %s\n", 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) : %s\n", 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 : %s\n", 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=%d\n"), 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=%d\n"), 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) : %s\n", dw, buf);
   }


   return 0; 
}
  • 写回答

3条回答 默认 最新

  • oyljerry 2015-07-11 14:27
    关注

    你客户端也要像服务端那样也创建一个对应事件的管道,然后让服务端反向给你数据。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 求差集那个函数有问题,有无佬可以解决
  • ¥15 【提问】基于Invest的水源涵养
  • ¥20 微信网友居然可以通过vx号找到我绑的手机号
  • ¥15 寻一个支付宝扫码远程授权登录的软件助手app
  • ¥15 解riccati方程组
  • ¥15 display:none;样式在嵌套结构中的已设置了display样式的元素上不起作用?
  • ¥15 使用rabbitMQ 消息队列作为url源进行多线程爬取时,总有几个url没有处理的问题。
  • ¥15 Ubuntu在安装序列比对软件STAR时出现报错如何解决
  • ¥50 树莓派安卓APK系统签名
  • ¥65 汇编语言除法溢出问题