我正在转换一个应用程序,该应用程序在两个服务之间有一个非常简单的心跳/状态监视连接。由于现在除了windows之外,还需要在linux上运行,我想我应该使用boost(v1.51,我无法升级-linux编译器太旧了,windows编译器是visual studio 2005)来完成使其与平台无关的任务(考虑到,我真的不希望有两个代码文件,每个操作系统一个,或者在整个代码中乱丢#defines,因为boost提供了令人愉快的阅读可能性(在我办理入住并忘记此代码后6个月!)
我现在的问题是连接超时了。事实上,它根本不起作用。
第一次发送"状态"消息时,服务器端会收到该消息,并发回相应的响应。然后,服务器端返回到套接字上等待另一条消息。客户端(此代码),再次发送"状态"消息。。。但这一次,服务器从未接收到它,readsome()调用会阻塞,直到套接字超时。我觉得真的很奇怪
服务器端没有更改。唯一改变的是,我将客户端代码从基本的winsock2套接字更改为此代码。以前,它连接并循环发送/recv调用,直到程序中止或收到"锁定"消息。
为什么随后的调用(发送)会在套接字上无声地发送任何东西失败,我需要调整什么才能恢复简单的发送/接收流?
#include <boost/signals2/signal.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
using boost::asio::ip::tcp;
using namespace std;
boost::system::error_code ServiceMonitorThread::ConnectToPeer(
tcp::socket &socket,
tcp::resolver::iterator endpoint_iterator)
{
boost::system::error_code error;
int tries = 0;
for (; tries < maxTriesBeforeAbort; tries++)
{
boost::asio::connect(socket, endpoint_iterator, error);
if (!error)
{
break;
}
else if (error != make_error_code(boost::system::errc::success))
{
// Error connecting to service... may not be running?
cerr << error.message() << endl;
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
}
}
if (tries == maxTriesBeforeAbort)
{
error = make_error_code(boost::system::errc::host_unreachable);
}
return error;
}
// Main thread-loop routine.
void ServiceMonitorThread::run()
{
boost::system::error_code error;
tcp::resolver resolver(io_service);
tcp::resolver::query query(hostnameOrAddress, to_string(port));
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
error = ConnectToPeer(socket, endpoint_iterator);
if (error && error == boost::system::errc::host_unreachable)
{
TerminateProgram();
}
boost::asio::streambuf command;
std::ostream command_stream(&command);
command_stream << "statusn";
boost::array<char, 10> response;
int retry = 0;
while (retry < maxTriesBeforeAbort)
{
// A 1s request interval is more than sufficient for status checking.
boost::this_thread::sleep_for(boost::chrono::seconds(1));
// Send the command to the network monitor server service.
boost::asio::write(socket, command, error);
if (error)
{
// Error sending to socket
cerr << error.message() << endl;
retry++;
continue;
}
// Clear the response buffer, then read the network monitor status.
response.assign(0);
/* size_t bytes_read = */ socket.read_some(boost::asio::buffer(response), error);
if (error)
{
if (error == make_error_code(boost::asio::error::eof))
{
// Connection was dropped, re-connect to the service.
error = ConnectToPeer(socket, endpoint_iterator);
if (error && error == make_error_code(boost::system::errc::host_unreachable))
{
TerminateProgram();
}
continue;
}
else
{
cerr << error.message() << endl;
retry++;
continue;
}
}
// Examine the response message.
if (strncmp(response.data(), "normal", 6) != 0)
{
retry++;
// If we received the lockdown response, then terminate.
if (strncmp(response.data(), "lockdown", 8) == 0)
{
break;
}
// Not an expected response, potential error, retry to see if it was merely an aberration.
continue;
}
// If we arrived here, the exchange was successful; reset the retry count.
if (retry > 0)
{
retry = 0;
}
}
// If retry count was incremented, then we have likely encountered an issue; shut things down.
if (retry != 0)
{
TerminateProgram();
}
}
当streambuf
被直接提供给I/O操作作为缓冲区时,I/O操作将通过提交读取数据或消耗写入数据来适当地管理输入序列。因此,在以下代码中,command
在第一次迭代后为空:
boost::asio::streambuf command;
std::ostream command_stream(&command);
command_stream << "statusn";
// `command`'s input sequence contains "statusn".
while (retry < maxTriesBeforeAbort)
{
...
// write all of `command`'s input sequence to the socket.
boost::asio::write(socket, command, error);
// `command.size()` is 0, as the write operation will consume the data.
// Subsequent write operations with `command` will be no-ops.
...
}
一种解决方案是使用std::string
作为缓冲区:
std::string command("statusn");
while (retry < maxTriesBeforeAbort)
{
...
boost::asio::write(socket, boost::asio::buffer(command), error);
...
}
有关streambuf
用法的更多详细信息,请考虑阅读此答案。