C++ Boost/ASIO 服务器与客户端
C++ boost/asio server with client
正在为 p2p 应用程序进行异步网络编程,我遇到了麻烦。我的应用程序必须是服务器和客户端。当服务器收到请求它必须将其广播到其他服务器k
。我认为 boost::asio 示例的 HTTP 服务器 3 示例可以很好地工作,其中包含异步客户端的实现(作为一个类(。上面提到的客户端类(来自 boost::asio 客户端示例(如下:
ClientIO::ClientIO(boost::asio::io_service& io_service, tcp::resolver::iterator endpoint_iterator)
: _io_service(io_service),
strand_(io_service),
resolver_(io_service),
socket_(io_service)
{
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
boost::bind(&ClientIO::handle_after_connect, this,
boost::asio::placeholders::error, ++endpoint_iterator));
}
void ClientIO::write(G3P mex)
{
_io_service.post(boost::bind(&ClientIO::writeMessage, this, mex));
}
void ClientIO::writeMessage(G3P mex)
{
bool write_in_progress = !messages_queue_.empty();
messages_queue_.push_back(mex);
if (!write_in_progress)
{
char* message=NULL;
boost::system::error_code ec;
if (messages_queue_.front().opcode == DATA)
{
message=(char*)malloc((10800)*sizeof(char));
}
else
message=(char*)malloc(1024*sizeof(char));
boost::asio::streambuf request;
std::ostream request_stream(&request);
serializeMessage(message, messages_queue_.front());
request_stream << message;
boost::asio::async_write(socket_, boost::asio::buffer(message, strlen(message)),
strand_.wrap(
boost::bind(&ClientIO::handle_after_write, this,
boost::asio::placeholders::error)));
free(message);
}
}
void ClientIO::readMessage()
{
boost::asio::async_read(socket_, data_,
boost::bind(&ClientIO::handle_after_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
));
}
void ClientIO::stop()
{
socket_.shutdown(tcp::socket::shutdown_both);
socket_.close();
}
void ClientIO::handle_after_connect(const boost::system::error_code& error,
tcp::resolver::iterator endpoint_iterator)
{
if (error)
{
if (endpoint_iterator != tcp::resolver::iterator())
{
socket_.close();
tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
boost::bind(&ClientIO::handle_after_connect,this,
boost::asio::placeholders::error, ++endpoint_iterator));
}
}
else
{
}
}
void ClientIO::handle_after_read(const boost::system::error_code& error, std::size_t bytes_transferred)
{
if (bytes_transferred > 0)
{
std::istream response_stream(&data_);
std::string mex="";
std::getline(response_stream, mex);
deserializeMessage(&reply_,mex);
if (reply_.opcode == REPL)
{
cout << "ack received" << endl;
}
}
if (error)
{
ERROR_MSG(error.message());
}
}
void ClientIO::handle_after_write(const boost::system::error_code& error)
{
if (error)
{
// ERROR_MSG("Error in write: " << error.message());
}
else
{
messages_queue_.pop_front();
if (!messages_queue_.empty())
{
cout << "[w] handle after write" << endl;
char* message;
if (messages_queue_.front().opcode == DATA)
{
message=(char*)malloc((10800)*sizeof(char));
}
else
message=(char*)malloc(1024*sizeof(char));
boost::asio::streambuf request;
std::ostream request_stream(&request);
serializeMessage(message, messages_queue_.front());
request_stream << message;
boost::asio::async_write(socket_, boost::asio::buffer(message, strlen(message)),
strand_.wrap(
boost::bind(&ClientIO::handle_after_write, this,
boost::asio::placeholders::error)));
}
boost::asio::async_read_until(socket_, data_,"rn",
strand_.wrap(
boost::bind(&ClientIO::handle_after_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred)));
}
}
ClientIO::~ClientIO()
{
cout << "service stopped" << endl;
}
}
当服务器收到新请求时,它会启动一个新的 DataManagement 类表单连接,经过一些计算后,写入一个队列使用上述类到其他服务器(这里只有一个(,并且在每次写入时必须对应一个 ack
client --write-> server ---write->
|--server1
server <--ACK----</
为了实现这一点,我创建了一个io_service实例 (io_service_test( 作为类变量,并在 DataManagement 构造函数中使用以下内容对其进行实例化:
DataManagement::DataManagement(){
tcp::resolver resolver(io_service_test);
tcp::resolver::query query(remotehost, remoteport);
tcp::resolver::iterator iterator = resolver.resolve(query);
cluster = new cluster_head::ClusterIO(io_service_test,iterator);
io_service_test.run_one();
}
然后,在计算之后,发送数据:
void DataManagement::sendTuple( . . . ){
. . .
io_service_test.reset();
io_service_test.run();
for (size_t i=0; i<ready_queue.size() ;i++)
{
cluster->write(fragTuple);
}
}
对应的是以相同的方式修改的相同 http proxy3 示例(没有客户端类(。问题是有时一切正常,有时失败并且我得到堆栈跟踪,有时它永远不会停止,甚至是分段错误。我认为问题已经关闭了io_service管理和类方法的生活,但我无法弄清楚。
- 有什么想法吗?
- 您是否有一些适合这种情况的示例,或者实现它的虚拟类?
简要回顾了代码,我看到了以下问题。
ClientIO::writeMessage
方法向收件人发送错误的信息,因为它- 为消息分配内存
- 调用
boost::asio::async_write
,它不发送任何数据,而只将请求放入内部 ASIO 的请求队列,即消息将在某个时间发送。boost::asio::buffer
不会复制邮件。它只存储对它的引用。 - 调用
free(message
(。即,当排队的写入请求将被执行时,分配给消息的内存可以被覆盖。
ClientIO::handle_after_write
中的内存泄漏。消息已分配但未释放。ClientIO::readMessage
的boost::asio::async_read
方法不会被strand_.wrap
调用包装。
为了避免问题 #1 和 #2 需要使用类似于 ASIO 缓冲区示例的 shared_const_buffer
类的东西。要解决此问题 #3,必须以与boost::asio::async_write
调用相同的方式使用 strand_.wrap
调用。
相关文章:
- "unknown ca"自生成的 CA、证书和客户端/服务器
- Java 客户端C++服务器数据发送/接收问题
- ZMQ - 客户端服务器:客户端意外关闭,服务器如何检测到?
- 用于本地网络运行的客户端服务器体系结构
- TCP套接字(客户端-服务器)recv()返回-1值
- C++启动另一个程序(客户端-服务器)的程序
- C++客户端/服务器聊天应用程序 - 从 Ubuntu 命令窗口扫描输入
- UDP客户端/服务器程序在不同的IP和端口上通信超过2个插座
- 为什么在此 UDP 客户端/服务器示例中没有必要绑定客户端套接字?
- TCP在客户端服务器之间传输时,数据是否有任何限制
- 是否可以添加多个服务器地址?(Asio,客户端>服务器)
- 通过TCP在客户端/ C#服务器之间传输文件C++
- TCP 客户端服务器程序
- 客户端服务器回声程序进入UDP的僵局
- 如何制作具有同步数据读/写功能的多客户端服务器
- Qt,客户端-服务器关系
- Winsock 简单客户端服务器,接收失败
- 在C++中对客户端/服务器应用进行单元测试
- 在客户端/服务器计算器C 方面遇到麻烦
- 客户端服务器简单示例非块