C++ 和 Java 应用程序之间的 NamedPipe 进程间

Posted

技术标签:

【中文标题】C++ 和 Java 应用程序之间的 NamedPipe 进程间【英文标题】:NamedPipe interprocess between c++ and Java application 【发布时间】:2015-01-23 06:25:27 【问题描述】:

我需要从 C++ 端启动一个命名管道服务器,并让一个 Java 应用程序从管道中读取。

对于创建管道的 C++ 端,我遵循了 MSDN 中的示例: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365603(v=vs.85).aspx

从Java端,我做了一段hacky代码来测试:

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++ 端代码:

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;
            
        
    

它可以毫无问题地连接到管道,但唯一的问题是 java 端无法获取在 C++ 端写入的数据,直到 C++ 进程完成(我的意思是从 VS 终止调试器)。

只要我的 C++ 进程仍在运行,它就会挂在 readLine 点: line = pipe.readLine()

有人对此有任何想法吗?

【问题讨论】:

各个方向的读写顺序是什么?如果客户端只需要一堆数据并且服务器知道客户端正在等待,则服务器可能会刷新(并关闭)。 使用套接字可能更健壮。 为了澄清,我实际上从 MSDN 示例中删除了读取部分。所以服务器只写入管道 我实际上尝试从 C++ 端调用刷新函数并尝试关闭句柄,但也不起作用.. 我避免使用套接字的原因是 C++ 应用程序已经是客户端应用程序并通过套接字连接到 c++ 服务器,所以我不想让事情复杂化 【参考方案1】:

据我所知 - 如果您在服务器端使用完全相同的 MSDN 代码 - 服务器在将任何内容写入管道之前正在等待输入。如果您的客户端从不发送任何内容,那么pipe.readLine 将阻塞,直到连接断开。

Java 不是我的菜,但我猜测来自服务器的响应还必须包含一个换行符,以便 readLine 返回。

【讨论】:

这显然与客户端完成后可以读取数据的观察结果相矛盾 - 因此无论如何都会写入,只是不会从缓冲区中刷新(在 C++ 程序中)。 @laune OP 没有显示任何输出,所以 readLine 可能只是返回一个空字符串 @laune,这就是我的想法,但即使我试图冲洗缓冲区甚至关闭手柄......也没有运气 其实,@gmbeard,你是对的。显然我错过了消息中的换行符。所以 Java 的 readLine 函数被阻塞在那里等待。谢谢你。 @laune 不,这根本不矛盾。 readLine() 将在流的末尾返回一个不完整的行。【参考方案2】:

如果您在 readLine() 中被阻止,则对等方不会发送线路。对等体退出时解除阻塞的原因是阅读器遇到了流尾,并返回了到目前为止接收到的数据。

您需要找出对等方正在发送的内容并为其使用合适的读取方法。显然不是线条,所以readLine() 是不适合这项工作的工具。

【讨论】:

真;我只是想先启动 namedpipe 客户端-服务器,然后我可以将消息放入场景中;所以我只是破解了java代码来做一个快速测试……现在我应该正确地修复它们。

以上是关于C++ 和 Java 应用程序之间的 NamedPipe 进程间的主要内容,如果未能解决你的问题,请参考以下文章

如何归档 java 和 c++ 应用程序之间的分布式(数据库)事务?

Windows中Java应用程序和C++应用程序之间的同步

Java的静态成员和C++的静态成员之间的区别[关闭]

C++ 和 Java 对象通信

C/C++编程笔记:盘点Java和C++之间的相似之处!

Java和C++进程之间的通信[重复]