问题描述
我有一台机器同时运行一些 C++ 应用程序和一个 Node.js 服务器。
用例: 我希望能够触发我的 C++ 应用程序并使其将一些数据(比如一个字符串)传递到套接字文件中。然后我的 Node.js 服务器将从套接字中获取该数据并通过 TCP 端口将其打印在某个网页上(此处/尚未包含代码)。反过来也应该如此。
到目前为止我所做的:
我能够使用以下代码将我的 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
和以下输出 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;
我得到以下输出:
/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.
时,它会运行,但我的 Node.js 服务器停止运行并且 nc -U /tmp/sock
失去连接。
.write() 和 .write_some() 函数似乎都不起作用。
我认为我错过了一些微不足道的东西,或者我没有遵循 Unix 套接字通信的基本概念。
问题:
- 是否可以使用一个 Node.js 服务器应用程序同时侦听 TCP 端口和 UNIX 套接字?
- 根据我的输入判断,我是否正确理解了 unix socket 通信的概念?
- 我如何从 C++ 中读取或写入从/到套接字,最好使用 C++ boost/asio 库。但不一定需要:-)
- 我问的问题是否正确?
如您所见,我对这些主题不太熟悉。如果我没有相应地解决我的问题并且不够准确,那是因为我缺乏经验。
非常感谢。让我们进行富有成果的讨论。
解决方法
哦,糟糕。错误一目了然:
::unlink("/tmp/sock"); // Remove previous binding.
移除插座。如果您想连接到它,那可不好。
删除该行使其工作:
passed setup section
passed connection: Success
before sending
after sending
在听者方面:
我想这是可以预料的,因为客户端尚未完成。
,免责声明: 我让它与 TCP 套接字一起工作,但我想看看它如何与 unix 套接字一起使用。再打开一个端口可能会导致潜在的安全威胁(如果我错了,请纠正我)。因此,如果您(sehe)或有人知道如何实现这一点,请随时分享。由于我无法在 Internet 上的搜索中找到此内容,因此它也可能对其他人有所帮助。
我现在做了什么:
- 创建一个监听两个端口的 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',res) => {
res.sendFile(__dirname + "/" + "index.html");
});
app.listen(si_port,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
我可以轻松地在该端口上发送随机字符串。
使用附加参数和字符串执行我的二进制文件,我能够从我的 C++ 发送一些数据:./clientcpp 127.0.0.1 6666 "HELLO from C++"
。这是输出:
再次非常感谢。