- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试使用 async_read
和 async_write
向服务器发出简单的 tcp 请求并设置超时。
问题是 async_read
在尝试读取直到传输结束时给出错误,在第一个 '\n' 上它返回错误(文件结束)。
逐行读取字符串时(当eots->at(last_request) = '\n')时,它成功读取了整个响应。
if(eots->at(last_request)=="") // read until end
{
boost::asio::async_read(
socket_
, input_buffer_
, boost::asio::transfer_at_least(1) // read untill end or error
, boost::bind(&tcp_client::do_Requests_read_handle, this, boost::asio::placeholders::error)
);
}else
{
boost::asio::async_read_until(
socket_
, input_buffer_
, eots->at(last_request) // read until current request end of transmission sign/string or error
, boost::bind(&tcp_client::do_Requests_read_handle, this, _1)
);
}
这是预期的行为吗?我做得对吗?
为了测试,我尝试进行 whois 查询 (args whois.iana.org 43 com
)。
完整代码:
/*
* MK async TCP
* contains basic definitions for extractions and string filtering
*
*/
#ifndef MK_ASYNC_TCP_HPP
#define MK_ASYNC_TCP_HPP
//
// async_tcp_client.cpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/placeholders.hpp>
//#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
using boost::asio::deadline_timer;
using boost::asio::ip::tcp;
//
// This class manages socket timeouts by applying the concept of a deadline.
// Some asynchronous operations are given deadlines by which they must complete.
// Deadlines are enforced by an "actor" that persists for the lifetime of the
// tcp_client object:
//
// +----------------+
// | |
// | check_deadline |<---+
// | | |
// +----------------+ | async_wait()
// | |
// +---------+
//
// If the deadline actor determines that the deadline has expired, the socket
// is closed and any outstanding operations are consequently cancelled.
//
// Connection establishment involves trying each endpoint in turn until a
// connection is successful, or the available endpoints are exhausted. If the
// deadline actor closes the socket, the connect actor is woken up and moves to
// the next endpoint.
//
// +---------------+
// | |
// | start_connect |<---+
// | | |
// +---------------+ |
// | |
// async_- | +----------------+
// connect() | | |
// +--->| handle_connect |
// | |
// +----------------+
// :
// Once a connection is :
// made, the connect :
// actor forks in two - :
// :
// an actor for reading : and an actor for
// inbound messages: : sending heartbeats:
// :
// +------------+ : +-------------+
// | |<- - - - -+- - - - ->| |
// | start_read | | start_write |<---+
// | |<---+ | | |
// +------------+ | +-------------+ | async_wait()
// | | | |
// async_- | +-------------+ async_- | +--------------+
// read_- | | | write() | | |
// until() +--->| handle_read | +--->| handle_write |
// | | | |
// +-------------+ +--------------+
//
// The input actor reads messages from the socket, where messages are delimited
// by the newline character. The deadline for a complete message is 30 seconds.
//
// The heartbeat actor sends a heartbeat (a message that consists of a single
// newline character) every 10 seconds. In this example, no deadline is applied
// message sending.
//
class tcp_client
{
public:
tcp_client(boost::asio::io_service& io_service, std::vector<std::string> * requests , std::vector<std::string> * responses , std::vector<std::string> * eots, unsigned int request_timeout = 30, unsigned int connect_timeout = 10)
: stopped_(false),
socket_(io_service),
deadline_(io_service),
heartbeat_timer_(io_service),
requests(requests),
responses(responses),
eots(eots),
request_timeout(request_timeout),
connect_timeout(connect_timeout)
{
if(eots->size()==0)
{
for(unsigned long i=0 ; i<(requests->size()-1); i++)
{
eots->push_back("\n");
}
eots->push_back("");
}
if(responses->size()==0)
{
responses->resize(requests->size());
}
if( (eots->size() != requests->size()) || (requests->size() != responses->size()) )
{
std::cerr<<std::endl<<"wrong nr of parameters"<<std::endl;
return;
}
}
// Called by the user of the tcp_client class to initiate the connection process.
// The endpoint iterator will have been obtained using a tcp::resolver.
void start(tcp::resolver::iterator endpoint_iter)
{
// Start the connect actor.
start_connect(endpoint_iter);
// Start the deadline actor. You will note that we're not setting any
// particular deadline here. Instead, the connect and input actors will
// update the deadline prior to each asynchronous operation.
deadline_.async_wait(boost::bind(&tcp_client::check_deadline, this));
}
// This function terminates all the actors to shut down the connection. It
// may be called by the user of the tcp_client class, or by the class itself in
// response to graceful termination or an unrecoverable error.
void stop()
{
stopped_ = true;
boost::system::error_code ignored_ec;
socket_.close(ignored_ec);
deadline_.cancel();
heartbeat_timer_.cancel();
}
private:
void start_connect(tcp::resolver::iterator endpoint_iter)
{
if (endpoint_iter != tcp::resolver::iterator())
{
std::cout << "Trying " << endpoint_iter->endpoint() << "...\n";
// Set a deadline for the connect operation.
deadline_.expires_from_now(boost::posix_time::seconds(60));
// Start the asynchronous connect operation.
socket_.async_connect(endpoint_iter->endpoint(),
boost::bind(&tcp_client::handle_connect,
this, _1, endpoint_iter));
}
else
{
// There are no more endpoints to try. Shut down the client.
stop();
}
}
void handle_connect(const boost::system::error_code& ec, tcp::resolver::iterator endpoint_iter)
{
if (stopped_)
return;
// The async_connect() function automatically opens the socket at the start
// of the asynchronous operation. If the socket is closed at this time then
// the timeout handler must have run first.
if (!socket_.is_open())
{
std::cout << "Connect timed out\n";
// Try the next available endpoint.
start_connect(++endpoint_iter);
}
// Check if the connect operation failed before the deadline expired.
else if (ec)
{
std::cout << "Connect error: " << ec.message() << "\n";
// We need to close the socket used in the previous connection attempt
// before starting a new one.
socket_.close();
// Try the next available endpoint.
start_connect(++endpoint_iter);
}
// Otherwise we have successfully established a connection.
else
{
std::cout << "Connected to " << endpoint_iter->endpoint() << "\n";
boost::asio::socket_base::keep_alive option(true);
socket_.set_option(option);
//~ // Start the input actor.
//~ start_read();
//~ // Start the heartbeat actor.
//~ start_write();
deadline_.expires_from_now(boost::posix_time::seconds(this->request_timeout));
do_Requests_write();
}
}
void handle_Requests_finish()
{
if(last_request<requests->size())
{
last_request++;
do_Requests_write();
}else
{
stop();
}
}
void do_Requests_write()
{
if (stopped_)
return;
// Start an asynchronous operation to send a heartbeat message.
boost::asio::async_write(
socket_
, boost::asio::buffer(requests->at(last_request)+"\n")
, boost::bind(&tcp_client::do_Requests_write_handle, this, _1)
);
}
void do_Requests_write_handle(const boost::system::error_code& ec)
{
if (stopped_)
return;
if (!ec)
{
do_Requests_read();
}
else
{
std::cout << "Error do_Requests_write_handle: " << ec.message() << "\n";
stop();
}
}
void do_Requests_read()
{
// Set a deadline for the read operation.
deadline_.expires_from_now(boost::posix_time::seconds(this->request_timeout));
// Start an asynchronous operation to read a newline-delimited message.
if(eots->at(last_request)=="") // read untill end
{
boost::asio::async_read(
socket_
, input_buffer_
, boost::asio::transfer_at_least(1) // read untill end or error
, boost::bind(&tcp_client::do_Requests_read_handle, this, boost::asio::placeholders::error)
);
}else
{
boost::asio::async_read_until(
socket_
, input_buffer_
, eots->at(last_request) // read untill current request end of transmission sign/string or error
, boost::bind(&tcp_client::do_Requests_read_handle, this, _1)
);
}
}
void do_Requests_read_handle(const boost::system::error_code& ec)
{
if (stopped_)
return;
if (!ec)
{
// Extract the newline-delimited message from the buffer.
//~ std::string line;
//~ std::istream is(&input_buffer_);
//~ std::getline(is, line);
std::istream response_istream(&input_buffer_);
std::string response;
response_istream >> response;
// Empty messages are heartbeats and so ignored.
std::cout << "Received: " << response << "\n";
responses->at(last_request)+=response+"\n";
//~ if (!line.empty())
//~ {
//~ std::cout << "Received: " << line << "\n";
//~ }
do_Requests_read();
}
else
{
std::cout<<(std::string)"Error on receive: " + ec.message() + "\n";
responses->at(last_request)+= (std::string)"Error on receive: " + ec.message() + "\n";
handle_Requests_finish();
}
}
void check_deadline()
{
if (stopped_)
return;
// Check whether the deadline has passed. We compare the deadline against
// the current time since a new asynchronous operation may have moved the
// deadline before this actor had a chance to run.
if (deadline_.expires_at() <= deadline_timer::traits_type::now())
{
// The deadline has passed. The socket is closed so that any outstanding
// asynchronous operations are cancelled.
socket_.close();
// There is no longer an active deadline. The expiry is set to positive
// infinity so that the actor takes no action until a new deadline is set.
deadline_.expires_at(boost::posix_time::pos_infin);
}
// Put the actor back to sleep.
deadline_.async_wait(boost::bind(&tcp_client::check_deadline, this));
}
private:
bool stopped_;
tcp::socket socket_;
boost::asio::streambuf input_buffer_;
deadline_timer deadline_;
deadline_timer heartbeat_timer_;
std::vector<std::string> *requests, *responses, *eots;
unsigned int last_request=0;
unsigned int request_timeout = 30;
unsigned int connect_timeout = 10;
};
int main(int argc, char* argv[])
{
std::vector<std::string> requests, responses, eots;
try
{
if (argc < 4)
{
std::cerr << "Usage: tcp_client <host> <port> <query1> <query2> <query3> [..]\n";
return 1;
}
for(int i = 3; i<argc ; i++ )
{
requests.push_back(argv[i]);
eots.push_back("");
responses.push_back("");
}
boost::asio::io_service io_service;
tcp::resolver r(io_service);
tcp_client c(io_service,&requests,&responses,&eots);
c.start(r.resolve(tcp::resolver::query(argv[1], argv[2])));
io_service.run();
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
#endif // MK_ASYNC_TCP_HPP
最佳答案
async_read()
操作以 boost::asio::error::eof
错误代码完成,因为已到达文件末尾,而不是因为到达第一个 \n
时从 input_buffer_
逐字读取。
whois.iana.org:43
上对 com
的响应是 1830 字节。
$ nc whois.iana.org 43 | wc --bytesentercomenter1830
当 boost::asio::streambuf
提供给读取操作,它将尝试分配未指定大小的缓冲区,以便可以读取数据。 current implementation将尝试分配一个大小为 512 的缓冲区。因此,如果接收到 1830 个字节,并且每次读取操作读取缓冲区最大值为 512 字节,那么所有接收到的字节将在第 4 次读取操作中被读取。因此,第 5 次读取操作将导致文件结束。
async_read_until()
的完成条件导致行为略有不同。当 streambuf 包含指定的定界符或发生错误时,此操作被视为完成。当 async_read_until()
完成时,streambuf 可能包含分隔符之外的其他数据。如果 streambuf 的附加数据包含分隔符,则随后对 async_read_until()
的调用将满足其完成条件,而无需调用 AsyncReadStream
的 async_read_some( )
函数。
关于c++ - boost::asio::async_read 在换行符上返回文件结尾错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22663063/
我一直在努力理解 boost 的 http server 3 example 中的逻辑.此示例中的请求在 connection.cpp 中的 start() 方法中读取,该方法调用: socket_.
我搜索了其他帖子,但没有找到任何相关内容。现在,我有一个由 header 和正文组成的协议(protocol)。协议(protocol)是这样的:Z24,91009802,123456789ABCDE
我正在尝试创建一个 TCP 服务器,其中 Start() 方法会阻塞,直到连接被接受,然后开始一系列异步读取。我有以下代码,当我使用 telnet 连接时,我得到以下输出: Waiting for a
简介 我正在学习c++ 和boost/asio 来实现分布式系统,所以我需要创建一个异步tcp 服务器。服务器像回声服务器一样工作,但您需要先发出请求(例如,通过套接字发送文本),服务器只响应 pi
我对 boost::async_read() 有疑问。 在网上,我发现有一个函数read_at_least(n)。但我正在寻找类似 read_max() 的函数,它可以读取最大字节数。 问题是我有不同
我有以下代码: void GnutellaApp::HandleRead (boost::asio::ip::tcp::socket& socket) { char buf[128];
我目前正在带宽非常低的环境中测试我的网络应用程序。我目前有代码试图通过确保我仍在接收信息来确保连接良好。 传统上,我通过在我的 ReadHandler 函数中记录时间戳来完成此操作,这样每次它被调用时
我正在使用 Boost/ASIO 编写通过 TCP/IP 通信的 C++ 服务器和随附的客户端应用程序。我看到连续接收之间的延迟导致服务器和客户端之间的吞吐量低于预期。两边的代码大致看起来像 clas
在 Windows 上,我观察到如果 async_read 操作在串行端口上成功完成,我会立即启动另一个 async_read 操作来读取 n 字节,第二个 async_read 操作立即意外完成并成
我对一个简单的 boost asio TCP 对话有点疯狂。 我有一个服务器和一个客户端。我使用长度前缀的消息。客户端发送“一”,服务器响应“二”。所以这就是我看到的情况: 客户端发送,服务器接收,0
我不是很熟悉 boost::asio 的基础知识。我正在处理连接到 Web 服务器并读取响应的任务。响应在随机时间段抛出,即在生成响应时。 为此,我使用了 boost::beast 库,它包含在 bo
我正在测试我的一些协议(protocol)设计,但无法让连续的 async_read 工作。我的想法是创建一个通用的读取处理程序来输出接收到的数据(测试),然后检查它以执行协议(protocol)定义
我有以下代码,它是从我的真实代码中简化而来的,我试图在连接到子进程的 async_pipe 上执行 async_read。在子进程中,我调用“ls”。作为一个测试,我希望我的异步读取能够得到结果。它返
这是我当前的服务器代码。我使用 telnet 连接到服务器。 #include #include #include #include using boost::asio::ip::tcp; c
所以, 我一直在研究 Boost asio 函数和套接字(特别是异步读/写)。现在,我认为 boost::asio::async_read 只在网络连接传入新缓冲区时才调用处理程序...但是它不会停止
我正在尝试使用 Boost::asio 和 async_read 在使用串行端口的协议(protocol)中实现超时。 我已经使用同步读取完成了一个测试实现,它只适用于查找,但我的超时实现不起作用。
我有一个使用 Asio 与远程系统对话的项目。我已将所有 Asio 代码封装在一个类中,该类在构造函数中打开一个同步连接,然后提供一个公共(public)方法,以便该类的用户可以通过套接字进行写入。这
我正在使用 boost::asio 进行客户端和服务器应用程序之间的 TCP 通信,这两者都是我编写的。我最初是通过使用 boost::asio::read 的同步数据读取来编写此代码的。 sync_
我正在尝试编写基于 IO_Service 的异步 TCP 客户端,其中 Async_write 工作正常但 async_read 在无限循环中运行。在我尝试纠正这个问题的过程中,我发现在所有其他情况下
我正在尝试实现一个带有异步套接字的 ssl 客户端,它从服务器发送和接收 protobuf 消息。消息的格式是前 4 个字节表示消息的大小,后面是 (X),其余是具有 X 字节的响应消息。 问题是我不
我是一名优秀的程序员,十分优秀!