簡體   English   中英

如何使用 IPC(Unix 域套接字)在 Node.js(pref. Express 模塊)服務器和 C++ 應用程序之間進行本地通信

[英]How to communicate locally between a Node.js (pref. Express module) server and a C++ application using IPC (Unix Domain Sockets)

我有一台機器同時運行一些C++ 應用程序Node.js 服務器

用例:我希望能夠觸發我的 C++ 應用程序並將一些數據(比如說一個字符串)傳遞到一個套接字文件中。 然后我的 Node.js 服務器將從套接字中獲取該數據並通過 TCP 端口將其打印在某些 web 頁面上(此處/尚未包含代碼)。 同樣的事情也應該反過來發生。

到目前為止我所做的:我能夠使用以下代碼將Node.js 服務器中的一些字符串寫入套接字文件: server.js

var net = require('net');
var fs = require('fs');
var socketPath = '/tmp/sock';

fs.stat(socketPath, function(err) {
    if (!err) fs.unlinkSync(socketPath);
    var unixServer = net.createServer(function(localSerialConnection) {
        localSerialConnection.on('data', function(data) {
            // data is a buffer from the socket
                    console.log('Something happened!');
        });
        // write to socket with localSerialConnection.write()
                localSerialConnection.write('HELLO\n');
                localSerialConnection.write('I\'m\n');
                localSerialConnection.write('DOING something!\n');
                localSerialConnection.write('with the SOCKS\n');
    });
unixServer.listen(socketPath);
});

使用nc -U /tmp/sock和以下 output https://i.stack.imgur.com/ye2Dx.png 讀取內容。

當我運行我的 C++ 代碼時:

cpp_socket.cpp

#include <boost/asio.hpp>
#include <iostream>

int main() {
    using boost::asio::local::stream_protocol;
    boost::system::error_code ec;

    ::unlink("/tmp/sock"); // Remove previous binding.
    boost::asio::io_service service;
    stream_protocol::endpoint ep("/tmp/sock");
    stream_protocol::socket s(service);

    std::cout << "passed setup section" << std::endl;
    
    s.connect(ep);

    std::cout << "passed connection" << std::endl;

    std::string message = "Hello from C++!";
    
    std::cout << "before sending" << std::endl;
    boost::asio::write(s, boost::asio::buffer(message), boost::asio::transfer_all());
    /* s.write_some(boost::asio::buffer("hello world!"), ec); */
    std::cout << "after sending" << std::endl;

我得到以下 output:

/cpp_socket 
passed setup section
terminate called after throwing an instance of 'boost::wrapexcept<boost::system::system_error>'
  what():  connect: No such file or directory
Aborted (core dumped)

即使/tmp/sock文件仍然存在。

當我刪除::unlink("/tmp/sock"); // Remove previous binding. ::unlink("/tmp/sock"); // Remove previous binding. 它運行通過注釋,但我的 Node.js 服務器停止運行並且nc -U /tmp/sock失去連接。 the.write() 和 the.write_some() function 似乎都不起作用。

我假設我錯過了一些瑣碎的事情,或者我沒有遵循 unix 套接字通信的基本概念。

問題:

  1. 甚至可以用一個 Node.js 服務器應用程序同時監聽 TCP 端口和 UNIX 套接字嗎?
  2. 從我的輸入來看,我是否正確理解了 unix 套接字通信的概念?
  3. 如何從 C++讀取寫入套接字,最好使用 C++ boost/asio 庫。 但不一定是必要的:-)
  4. 我在問正確的問題嗎?

如您所見,我對這些主題沒有太多經驗。 如果我沒有相應地解決我的問題並且不夠精確,那是由於我缺乏經驗。

提前非常感謝。 讓我們進行富有成果的討論。

哦哦哦。 錯誤一目了然:

::unlink("/tmp/sock"); // Remove previous binding.

移除插座。 如果您想連接到它,那就不好了。

刪除該行使其工作:

passed setup section
passed connection: Success
before sending
after sending

在聽眾方面:

在此處輸入圖像描述

我猜這是意料之中的,因為客戶端還沒有完成。

免責聲明:我使它與 TCP sockets 一起工作,但我想看看它如何與 unix ZFFE33A3F6E3550641DABA01 一起使用。 再開放一個端口可能會導致潛在的安全威脅(如果我錯了,請糾正我)。 因此,如果您(sehe)或有人知道如何實現這一目標,請隨時分享。 由於我無法在互聯網上的搜索中找到此內容,因此它對其他人也可能有所幫助。

我現在做了什么:

  • 創建一個監聽兩個端口的 NodeJS 服務器。 一個用於網絡瀏覽器的端口,一個用於 C++ 應用程序的端口
  • 用一個端口連接 C++ 應用程序
  • 使用 telnet 發送字符串

server.js

const net = require('net');
const express = require('express');
const app = express();
const c_port = 6666;
const si_port = 8888;

//------------- From here Browser stream is handled -------------//

app.get('/', (req, res)=>{
  res.send('Hello from Node!');
});

app.get('/index.html', (req, res) => {
  res.sendFile(__dirname + "/" + "index.html");
});

app.listen(si_port,(req, res)=>{
  console.log(`Listening on http://localhost:${si_port}`);
});


//------------- From here C++ stream is handled -------------//

var server = net.createServer(function(c) { //'connection' listener
  console.log('client connected');
    c.on('end', function() {
    console.log('client disconnected');
  });
  c.write('hello\r\n');

  c.on('data', function(data){
  var read = data.toString();
  console.log(read);
    // var message = c.read();
    // console.log(message);
  })
  // c.pipe(c);
  c.write('Hello back to C++'); // But only if you shut down the server
});

server.listen(c_port, function() { //'listening' listener
  console.log(`Listening for input from C++ application on port:${c_port}`);
});

client.cpp

#include <iostream>
#include <boost/asio.hpp>

int main(int argc, char* argv[]) 
{

    if(argc != 4){
        std::cout<<"Wrong parameter\n"<<"Example usage ./client 127.0.0.1 1234 hello"<<std::endl;   
        return -1;
    }

    auto const address = boost::asio::ip::make_address(argv[1]);
    auto const port = std::atoi(argv[2]);
    std::string msg = argv[3];
    
    msg = msg + '\n';

    boost::asio::io_service io_service;
    
    //socket creation
    boost::asio::ip::tcp::socket socket(io_service);
    
    //connection
    boost::system::error_code ec;
    socket.connect( boost::asio::ip::tcp::endpoint( address, port ),ec);
    if(ec){std::cout<<ec.message()<<std::endl; return 1;}
    
    // request/message from client
    //const string msg = "Hello from Client!\n";
    boost::system::error_code error;
    boost::asio::write( socket, boost::asio::buffer(msg), error );

    if(error){
        std::cout << "send failed: " << error.message() << std::endl;
    }
    
    // getting response from server
    boost::asio::streambuf receive_buffer;
    boost::asio::read(socket, receive_buffer, boost::asio::transfer_all(), error);
    
    if( error && error != boost::asio::error::eof ){
        std::cout << "receive failed: " << error.message() << std::endl;
    }
    else{
        const char* data = boost::asio::buffer_cast<const char*>(receive_buffer.data());
        std::cout << data << std::endl;
  }
    return 0;
}

使用telnet localhost 6666我可以輕松地在該端口上發送隨機字符串。 使用額外的 arguments 和一個字符串執行我的二進制文件,我能夠從我的 C++: ./clientcpp 127.0.0.1 6666 "HELLO from C++"發送一些數據。 這是 output: 在此處輸入圖像描述

再次非常感謝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM