Windows命名管道客户端WriteFile失败,错误232 ERROR_NO_DATA仅与第一个客户端有关

时间:2014-08-10 11:59:56

标签: c++ winapi file-io pipe named-pipes

我已经实现了命名管道服务器和客户端。管道处于PIPE_READMODE_MESSAGE模式。我试图使用WriteFile从客户端向服务器发送消息。操作失败,GetLastError返回错误232 ERROR_NO_DATA。如果我连接第二个客户端,则操作成功并发送消息。 我尝试使用SetNamedPipeHandleState在同一管道句柄上进行其他操作,操作成功,所以我认为管道没问题。 从服务器发送到客户端的消息也是成功的。 我不认为这是一个缓冲区大小问题,因为我试图发送4个字节,并为管道定义512字节缓冲区。

有一个类似的主题:WriteFile on a named pipe sometimes returns ERROR_NO_DATA 但它并没有解决我的问题。 我在网上搜索了答案,但我找不到这样的东西。感谢任何帮助

服务器代码:

int CServer::Run(){
    BOOL   fConnected = FALSE;
    DWORD  dwThreadId = 0;
    HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
    //LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\IlyaPipe");
    LPTSTR lpszPipename = TEXT("IlyaPipe");
    CSingleLock ConnListLock(&server.ConnManager.ConnListMutex);
    CConnection* NewConn;
    CWnd* pWnd = AfxGetMainWnd();
    ASSERT_VALID(pWnd);
    // The main loop creates an instance of the named pipe and 
    // then waits for a client to connect to it. When the client 
    // connects, a thread is created to handle communications 
    // with that client, and this loop is free to wait for the
    // next client connect request. It is an infinite loop.

    //start connection manager thread.

    server.ConnManager.CreateThread();
    SendMessage(pWnd->m_hWnd, WM_SERVER_ONLINE, 0, 0);
    for (;;)
    {
        NewConn = new CConnection;
        NewConn->Create(
            lpszPipename,             // pipe name 
            PIPE_ACCESS_DUPLEX,       // read/write access 
            PIPE_TYPE_MESSAGE |       // message type pipe 
            PIPE_READMODE_MESSAGE |   // message-read mode 
            PIPE_WAIT,                // blocking mode 
            PIPE_UNLIMITED_INSTANCES, // max. instances  
            BUFSIZE,                  // output buffer size 
            BUFSIZE,                  // input buffer size 
            0,                        // client time-out 
            NULL);

        // Wait for the client to connect; if it succeeds, 
        // the function returns a nonzero value. If the function
        // returns zero, GetLastError returns ERROR_PIPE_CONNECTED. 

        NewConn->ConnectClient(NULL);
        //after succesful initialization, set read/write mode to blocking message mode.
        NewConn->SetMode(FALSE, TRUE);
        NewConn->ClientProcessID = (ULONG)NewConn->m_hPipe; //temporary value

        if (ConnListLock.Lock(INFINITE))
        {
            server.ConnManager.AddConnection((*NewConn));
            NewConn->SendConnectionID();
            ConnListLock.Unlock();
        }
        SendMessage(pWnd->m_hWnd, WM_CLIENT_ADDED, 0, 0);
    }
    //notify of server shut down
    SendMessage(pWnd->m_hWnd, WM_SERVER_OFFLINE, 0, 0);
    return (0);
}


void CNamedPipe::Create(LPCTSTR lpszName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD dwMaxInstances, DWORD dwOutBufferSize, 
                        DWORD dwInBufferSize, DWORD dwDefaultTimeOut, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
{
  //Validate our parameters
  ASSERT(!IsOpen());
  ASSERT(_tcslen(lpszName));

  //the class encapsulates creating the pipe name, all that is required is
  //a simple name for the pipe e.g. lpName = PJPIPE will create the pipe
  //name "\\.\PIPE\PJPIPE"
  CString sPipeName;
  sPipeName.Format(_T("\\\\.\\PIPE\\%s"), lpszName);

  m_hPipe = ::CreateNamedPipe(sPipeName, dwOpenMode, dwPipeMode, dwMaxInstances, dwOutBufferSize, dwInBufferSize, dwDefaultTimeOut, lpSecurityAttributes);
  if (m_hPipe == INVALID_HANDLE_VALUE)
    ThrowNamedPipeException();
}

客户:

int CServerConnection::Run(){

    BOOL   fSuccess = FALSE;
    DWORD  cbRead, cbToWrite, cbWritten, dwMode, dwEvent, dwError;
    LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\IlyaPipe");

    // Try to open a named pipe; wait for it, if necessary. 

    while (1)
    {
        hConnPipe = CreateFile(
            lpszPipename,   // pipe name 
            GENERIC_READ |  // read and write access 
            GENERIC_WRITE,
            0,              // no sharing 
            NULL,           // default security attributes
            OPEN_EXISTING,  // opens existing pipe 
            0,              // default attributes 
            NULL);          // no template file 

        // Break if the pipe handle is valid. 

        if (hConnPipe != INVALID_HANDLE_VALUE)
        {
            // The pipe connected; change to message-read mode. 

            dwMode = PIPE_READMODE_MESSAGE;
            fSuccess = SetNamedPipeHandleState(
                hConnPipe,    // 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 (0);
            }

            //get ID from server, for creating 'message from server' event
            if (!ReadMessage())
                return (0);
            //create event name string for message from server event.
            CString EventName;
            EventName.Format(_T("ILYA_PIPE_SERVER_SENT_"));
            EventName.AppendFormat(_T("%s"), m_ReplyBuff);
            //register to the event signaling a message was sent from server to client. should be created by server.
            hSendMsgEvent[1] = CreateEvent(NULL, TRUE, FALSE, EventName);
            if (GetLastError() != ERROR_ALREADY_EXISTS)
                return (0);
            //register to the event signaling a message was sent from server to client. should be created by server.
            EventName.Format(_T("ILYA_PIPE_CLIENT_SENT_"));
            EventName.AppendFormat(_T("%s"), m_ReplyBuff);
            m_hAlertServerEvent = CreateEvent(NULL, TRUE, FALSE, EventName);
            if (GetLastError() != ERROR_ALREADY_EXISTS)
                return (0);

            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 (0);
            //ExitInstance();
        }

        // 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 (0);
            //ExitInstance();

        }
    }


    //notify main window that connection to server established
    CWnd* pWnd = AfxGetMainWnd();
    ASSERT_VALID(pWnd);
    SendMessage(pWnd->m_hWnd, WM_CONNECTION_ESTABLISHED, 0, 0);




    //SendMessage(pWnd->m_hWnd, WM_CONNECTION_ESTABLISHED, 0, 0);
    //message send and receive loop
    while (1){
        dwEvent = WaitForMultipleObjects(1, hSendMsgEvent, FALSE, INFINITE);
        switch (dwEvent){
        //The application wants to send a request.
        case SEND_MSG_EVENT:
            if (SendMsg2Server())
                //set event notifing the server of sent message
                SetEvent(m_hAlertServerEvent);
            else
                dwError = GetLastError();
            ResetEvent(hSendMsgEvent[0]);
            break;

        //A message is waiting for you at the server
        case RECEIVE_MSG_EVENT:
            ReadMessage();
            ResetEvent(hSendMsgEvent[1]);
            break;

        //Invalid return from wait
        default :
            ExitProcess(0);

        }
    }



    //connectionStatus = true;

    // Write the reply to the pipe. 

    //CloseHandle(hPipe);

    return (0);

}



int CServerConnection::DisconnectFromServer()
{
    return 0;
}

void CServerConnection::PackMessage(const uint8 ActionType, const uint8 DeviceAddress,  const uint32 FileId,const uint32 Offset ){

    msg.ActionType = ActionType;
    msg.bSent = 1;
    msg.bReady = 0;
    msg.DeviceAddress = DeviceAddress;
    msg.FileId = FileId;
    msg.Offset = Offset;
}

BOOL CServerConnection::SendMsg2Server(){
    BOOL   fSuccess = FALSE;
    DWORD  cbWritten = 0, cbReplyBytes = 0, cbToWrite, dwMode;
    CString MsgStr;
    LPTSTR lpvMessage = TEXT("Default");

    //MsgStr.Format(_T("%d*%d"), msg.FileId, msg.ActionType);
    //cbToWrite = 2*sizeof(TCHAR)*(MsgStr.GetLength() + 1);

    cbToWrite = (lstrlen(lpvMessage) + 1)*sizeof(TCHAR);
    MsgStr.Format(TEXT("%d"), 1);
    cbToWrite = sizeof(MsgStr);

    dwMode = PIPE_READMODE_MESSAGE;
    fSuccess = SetNamedPipeHandleState(
        hConnPipe,    // pipe handle 
        &dwMode,  // new pipe mode 
        NULL,     // don't set maximum bytes 
        NULL);    // don't set maximum time 

    fSuccess = WriteFile(
        hConnPipe,              // pipe handle 
        MsgStr,
        cbToWrite,              // message length 
        &cbWritten,             // bytes written 
        NULL);

    return fSuccess;

}


//Read message from server
BOOL CServerConnection::ReadMessage(){
    BOOL   fSuccess = FALSE;
    DWORD cbBytesRead = 0;

    fSuccess = ReadFile(
        hConnPipe,              //pipe handle
        (LPVOID)m_ReplyBuff,    //Message buffer
        BUFSIZE,                //Maximal message size
        &cbBytesRead,           //actual bytes read
        NULL);

    return fSuccess;

}

0 个答案:

没有答案
相关问题