Я пишу синхронный клиент. Его частью является объект Connection
, который отвечает за фактическую отправку и получение данных. Вся библиотека написана с использованием класса Boost ASIO ip::tcp::socket
.Socket ReceiveTimeout на Linux
У меня есть тест, в котором клиент вызывает метод на сервере (который спит в течение 2 секунд) с тайм-аутом в 1 секунду. Мой код обнаружил, что выполнение заняло больше времени, чем запрошенное, но оно не вернулось вовремя. Вместо этого он возвращался после двух целых секунд.
я сузил проблему до receive
метода:
void Connection::receive(const mutable_buffers_1& buffers, const DurationType& timeout)
{
// to make sure it isn't 0 by mistake
auto actualTimeout = std::max(DurationType(milliseconds(1)), timeout);
SocketReceiveTimeoutOption timeoutOption(actualTimeout);
error_code ec;
_socket.set_option(timeoutOption, ec);
RPC_LOG(TRACE) << "Setting timeout " << actualTimeout << " returned: " << ec.message();
RPC_LOG(TRACE) << "Receiving...";
if (_socket.receive(buffers, MSG_WAITALL, ec) != buffer_size(buffers))
{
throw RpcCommunicationError("Did not receive the expected number of bytes from connection");
}
RPC_LOG(TRACE) << "Received! With error code: " << ec.message();
}
DurationType
является только удобством ЬурейиМ:
typedef boost::chrono::system_clock ClockType;
typedef ClockType::time_point::duration DurationType;
SocketReceiveTimeoutOption
вариант реализуется для сокетов:
template <int Name>
class SocketTimeoutOption
{
public:
#ifdef BSII_WINDOWS
SocketTimeoutOption(const DurationType& timeout) : _value(static_cast<DWORD>(boost::chrono::duration_cast<boost::chrono::milliseconds>(timeout).count())) {}
#else
SocketTimeoutOption(const DurationType& timeout) : _value(Utils::toTimeval(timeout)) {}
#endif
// Get the level of the socket option.
template <typename Protocol>
int level(const Protocol&) const
{
return SOL_SOCKET;
}
// Get the name of the socket option.
template <typename Protocol>
int name(const Protocol&) const
{
return Name;
}
// Get the address of the timeout data.
template <typename Protocol>
void* data(const Protocol&)
{
return &_value;
}
// Get the address of the timeout data.
template <typename Protocol>
const void* data(const Protocol&) const
{
return &_value;
}
// Get the size of the boolean data.
template <typename Protocol>
std::size_t size(const Protocol&) const
{
return sizeof(_value);
}
private:
#ifdef BSII_WINDOWS
DWORD _value;
#else
timeval _value;
#endif
};
typedef SocketTimeoutOption<SO_RCVTIMEO> SocketReceiveTimeoutOption;
typedef SocketTimeoutOption<SO_SNDTIMEO> SocketSendTimeoutOption;
И, наконец,
namespace Utils
{
inline
timeval toTimeval(const DurationType& duration)
{
timeval val;
auto seconds = boost::chrono::duration_cast<boost::chrono::seconds>(duration); // TODO: make sure this is truncated down in case there's fractional seconds
val.tv_sec = static_cast<long>(seconds.count());
auto micro = boost::chrono::duration_cast<boost::chrono::microseconds>(duration - seconds);
val.tv_usec = static_cast<long>(micro.count());
return val;
}
}
Проблема в том, что, хотя я указываю тайм-аут 1 с, метод receive
все еще занимает целые 2 секунды. Вот журнал:
2014-09-14 10: 27: 53.348383 | след | 0x007f24e50ae7c0 | Установка тайм-аута 999917107 наносекунды: Успех
2014-09-14 10: 27: 53.348422 | след | 0x007f24e50ae7c0 | Прием ...
2014-09-14 10: 27: 55.349152 | след | 0x007f24e50ae7c0 | Получено! С кодом ошибки: Успех
Как вы можете видеть, установка тайм-аута работала, но метод receive
занял 2 секунды.
Тот же код работает отлично в Windows.
'DurationType' и' SocketReceiveTimeoutOption' не определены. Если они типизированы для фактических типов повышения, пожалуйста, покажите typedefs или используйте фактические типы boost в вашем примере. –
Спасибо. Отредактированный исходный вопрос. Теперь я вижу, что возможно, что у меня ошибка в настройке параметра тайм-аута в случае Linux. Я проверю и обновлю. – Dina
Обновление: я думаю, что преобразование продолжительности в timeval в порядке. Я добавил несколько журналов и получил следующее: Преобразование 999718938 наносекунд в timeval Получено: 0 секунд + 999718 секунд – Dina