我有一个非常简单的 asio TCP 服务器:
using asio::ip::tcp;
class Client
{
public:
Client(tcp::socket&& openedSocket) : socket(std::move(openedSocket)), readBuffer(1024)
{
socket.async_read_some(asio::buffer(readBuffer.data(), readBuffer.size()), std::bind(&Client::handleRead, this, std::placeholders::_1, std::placeholders::_2));
}
private:
void handleRead(const asio::error_code& error, size_t numRead)
{
if(error)
{
std::cout << error.message() << std::endl;
}
else
{
std::cout << "Reading" << std::endl;
}
socket.async_read_some(asio::buffer(readBuffer.data(), readBuffer.size()), std::bind(&Client::handleRead, this, std::placeholders::_1, std::placeholders::_2));
}
tcp::socket socket;
std::vector<uint8_t> readBuffer;
};
class Server
{
public:
Server() : acceptor(context, tcp::endpoint(tcp::v4(), 3030))
{
try
{
startAccept();
context.run();
}
catch(const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
private:
void startAccept()
{
acceptor.async_accept(std::bind(&Server::handleAccept, this, std::placeholders::_1, std::placeholders::_2));
}
void handleAccept(const asio::error_code& error, tcp::socket socket)
{
if(!error)
{
clients.push_back(std::make_unique<Client>(std::move(socket)));
}
else
{
std::cout << error.message() << std::endl;
}
startAccept();
}
asio::io_context context;
tcp::acceptor acceptor;
std::vector<std::unique_ptr<Client>> clients;
};
此代码适用于从基本主函数成功读取,该函数除了实例化服务器外什么都不做。
但是,当我在 JUCE 应用程序中运行此代码时,从 JUCE 消息线程实例化服务器,与客户端的连接成功但所有读取都会导致错误“文件描述符错误”。
为什么会这样?
我们无法判断,因为我们没有看到代码。
我以前从未使用过 JUCE,但这是我的第一次使用,使用包含您的代码的基本 GUI 应用程序。我所做的唯一更改是允许服务器使用
thread_pool
作为上下文在后台运行。
#include <asio.hpp>
namespace SO {
using namespace std::placeholders;
using asio::ip::tcp;
class Client {
public:
Client(tcp::socket &&openedSocket)
: socket(std::move(openedSocket)), readBuffer(1024) {
startRead();
}
private:
void startRead() {
socket.async_read_some(asio::buffer(readBuffer),
bind(&Client::handleRead, this, _1, _2));
}
void handleRead(const asio::error_code &error, size_t numRead) {
std::cout << "Reading (" << error.message() << ", " << numRead << ")"
<< std::endl;
if (!error)
startRead();
}
tcp::socket socket;
std::vector<uint8_t> readBuffer;
};
class Server {
public:
Server() : acceptor(context, tcp::endpoint(tcp::v4(), 3030)) {
startAccept();
}
~Server() {
post(context, [this] {
acceptor.cancel();
acceptor.close();
});
}
private:
void startAccept() {
acceptor.async_accept(make_strand(context),
bind(&Server::handleAccept, this, _1, _2));
}
void handleAccept(const asio::error_code &error, tcp::socket socket) {
if (!error) {
clients.push_back(std::make_unique<Client>(std::move(socket)));
startAccept();
} else {
std::cout << error.message() << std::endl;
}
}
asio::thread_pool context;
tcp::acceptor acceptor;
std::vector<std::unique_ptr<Client>> clients;
};
} // namespace SO
//==============================================================================
class sehejuceApplication : public juce::JUCEApplication
{
std::shared_ptr<SO::Server> soTcpServer;
public:
//==============================================================================
sehejuceApplication() {}
const juce::String getApplicationName() override { return ProjectInfo::projectName; }
const juce::String getApplicationVersion() override { return ProjectInfo::versionString; }
bool moreThanOneInstanceAllowed() override { return true; }
//==============================================================================
void initialise (const juce::String& commandLine) override
{
// This method is where you should put your application's initialisation code..
mainWindow.reset (new MainWindow (getApplicationName()));
soTcpServer = std::make_shared<SO::Server>();
}
void shutdown() override
{
// Add your application's shutdown code here..
mainWindow = nullptr; // (deletes our window)
soTcpServer.reset();
}
// rest unmodified as autogenerated by Projucer
现场演示: