0

I need start a named pipe server from c++ side and get a java application to read from the pipe.

For the C++ side which creates the pipe, I followed the example from MSDN: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365603(v=vs.85).aspx

From Java end, I did a piece of hacky code to test:

Thread readerThread = new Thread( new Runnable()
    {
        @Override
        public void run()
        {
            String line = null;
            while( true )
            {
                try
                {
                    final RandomAccessFile pipe =
                            new RandomAccessFile( "\\\\\\\\.\\\\pipe\\\\smarts_interprocess", "r" );
                    while( null != ( line = pipe.readLine() ) )
                    {
                        s_logger.warning( line );
                    }
                }
                catch( IOException ex )
                {
                    s_logger.severe( ex.getMessage() );
                    try
                    {
                        Thread.sleep( 1000 );
                    }
                    catch( InterruptedException e )
                    {
                        s_logger.info( "nothing available, I will sleep for a second" );
                    }
                }
            }
        }
    } );
    readerThread.start();

C++ side code:

void Pipe::startMessageLoop()
{
    DWORD dwWait{};
    BOOL fSuccess;

    fPendingIO = ConnectToNewClient(m_inputHandle, &oOverlap_);

    while (true)
    {
        dwWait = ::WaitForSingleObject(oOverlap_.hEvent, INFINITE);

        if (dwWait == WAIT_FAILED)
        {
            ::CloseHandle(oOverlap_.hEvent);
            std::cout << "failed to WaitForSingleObject.." << std::endl;
        }

        if (fPendingIO)
        {
            DWORD cbRet;
            fSuccess = GetOverlappedResult(
                m_inputHandle,     // handle to pipe 
                &oOverlap_,        // OVERLAPPED structure 
                &cbRet,            // bytes transferred 
                FALSE);            // do not wait 

            switch (dwState)
            {
            // Pending connect operation 
            case CONNECTING_STATE:
                if (!fSuccess)
                {
                    printf("Error %d.\n", GetLastError());
                    return;
                }
                dwState = WRITING_STATE;
                break;

                // Pending write operation 
            case WRITING_STATE:
                if (!fSuccess)
                {
                    DisconnectAndReconnect();
                    continue;
                }
                break;

            default:
            {
                printf("Invalid pipe state.\n");
                return;
            }
            }
        }


        std::string message = "naive message from server";
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        std::wstring data = converter.from_bytes(message.c_str());
        DWORD numBytesWritten = 0;

        switch (dwState)
        {           
            case WRITING_STATE:

                fSuccess = WriteFile(
                    m_inputHandle, // handle to our outbound pipe
                    data.c_str(), // data to send
                    wcslen(data.c_str()) * sizeof(wchar_t), // length of data to send (bytes)
                    &numBytesWritten, // will store actual amount of data sent
                    NULL // not using overlapped IO
                    );

                // FlushFileBuffers(m_inputHandle);
                // The write operation completed successfully. 
                if (fSuccess)
                {
                    fPendingIO = FALSE;                 
                    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
                    dwState = WRITING_STATE;
                    continue;
                }

                // The write operation is still pending. 
                if (!fSuccess && (GetLastError() == ERROR_IO_PENDING))
                {
                    fPendingIO = TRUE;
                    continue;
                }
                // An error occurred; disconnect from the client. 
                DisconnectAndReconnect();
                break;

            default:
            {
                printf("Invalid pipe state.\n");
                return;
            }
        }
    }
}

It can be connected to the pipe without any issue, but the only problem is that java end cannot get the data which was written on the c++ end until the C++ process finishes (terminates the debugger from VS I meant).

As long as my C++ process still running, it hangs at the point to readLine: line = pipe.readLine()

Anyone has any idea on this?

rzhomx
  • 85
  • 1
  • 12
  • What is the sequence of reads and writes in all directions? If the client just expects a bunch of data and the server knows that the client is waiting, the server might flush (and close). – laune Jan 23 '15 at 06:55
  • 1
    Using sockets might be more robust. – laune Jan 23 '15 at 06:56
  • To clarify, I actually remove the the reading part from the MSDN example.. So the server only write into the pipe – rzhomx Jan 23 '15 at 10:22
  • I actually tried to call the flush function from C++ side and also tried to close the handle, but not working either.. – rzhomx Jan 23 '15 at 10:24
  • The reason I am avoiding socket is that the C++ app is already a client appp and connected to c++ server via socket so I don't want to complicate things there – rzhomx Jan 23 '15 at 10:29
  • OK. But why RandomAccess? A straightforward BufferedReader will let you readLine. - I'm not sure what RandomAccess does on a named pipe, Windows or other OS. – laune Jan 23 '15 at 10:34
  • Although running more than one socket connection from one program shouldn't be an issue if blocking reads aren't used with a single thread. – laune Jan 23 '15 at 10:35
  • @laune It will read, but it won't let him send anything. He needs something bidirectional, and `RandomAccessFile` and `FileChannel` are the only choices. – user207421 Jan 27 '15 at 01:50

2 Answers2

1

From what I can tell - if you've used exactly the same MSDN code for your server side - the server is waiting for input before it writes anything to the pipe. If your client never sends anything then pipe.readLine will block until the connection is severed.

Java isn't my thing but I'm guessing that the response from the server must also contain a newline on order for readLine to return.

gmbeard
  • 674
  • 6
  • 19
  • This clearly contradicts the observation that data can be read after the client finishes - so it is written anyway, just not flushed from the buffer (in the C++ program). – laune Jan 23 '15 at 06:53
  • @laune OP doesn't show any output so `readLine` may just be returning an empty string – gmbeard Jan 23 '15 at 07:24
  • @laune, that is what I thought but even I tried to flush the bufer and even close the handle... No luck either – rzhomx Jan 23 '15 at 10:26
  • Actually, @gmbeard, you are right. Apparently I am missing the newline char from the message. so Java's readLine function is blocked waiting there. Thanks for that. – rzhomx Jan 27 '15 at 01:20
  • @laune No, it doesn't contradict it at all. `readLine()` will return an incomplete line at end of stream. – user207421 Jan 27 '15 at 01:51
  • @rzhomx Feel free to accept my answer if it has helped solve your problem – gmbeard Jan 27 '15 at 19:56
1

If you're blocked in readLine(), the peer isn't sending lines. The reason it unblocks when the peer exits is that the reader encounters end of stream, and returns the data received so far.

You need to find out what the peer is sending and use suitable read methods for it. Clearly it isn't lines, so readLine() is the wrong tool for the job.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • True; I was just trying to get namedpipe client - server up first and then i can fit my messages into the scene; so I just hacked up the java code to do a quick test though..now I should fix them properly. – rzhomx Jan 27 '15 at 01:28