У меня очень простой тест производительности сервера/клиента с использованием boost :: asio в Windows, и, похоже, он работает очень плохо. Я надеюсь, что я просто неправильно использую библиотеку и буду благодарен за любые советы.Плохая производительность boost.ASIO
У меня есть класс сеанса, который пишет длину сообщения, а затем записывает сообщение, а затем ждет, чтобы прочитать длину сообщения, а затем прочитать сообщение и продолжает делать это снова и снова без перерыва. Однако, когда я запускаю его локально на своем собственном компьютере, я получаю невероятно высокую производительность; когда я запускаю сервер на одном компьютере и клиент на другом компьютере, даже в той же сети, производительность замедляется, и для операции чтения/записи требуется целых 1 секунда.
Файл исходного кода сервера выглядит следующим образом:
#include <cstdlib>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;
using namespace std;
class Session {
public:
Session(io_service& ioService)
: m_socket(ioService) {}
tcp::socket& GetSocket() {
return m_socket;
}
void StartRead() {
m_messageSizeIterator = reinterpret_cast<char*>(&m_messageSize);
async_read(m_socket, buffer(m_messageSizeIterator, sizeof(m_messageSize)),
bind(&Session::HandleSizeRead, this, placeholders::error,
placeholders::bytes_transferred));
}
void StartWrite(const char* message, int messageSize) {
m_messageSize = messageSize;
m_message = new char[m_messageSize];
memcpy(m_message, message, m_messageSize);
async_write(m_socket, buffer(&m_messageSize, sizeof(int)),
bind(&Session::HandleSizeWritten, this, placeholders::error));
}
void HandleSizeRead(const system::error_code& error,
size_t bytes_transferred) {
if(!error) {
m_message = new char[m_messageSize];
async_read(m_socket, buffer(m_message, m_messageSize),
bind(&Session::HandleMessageRead, this, placeholders::error,
placeholders::bytes_transferred));
} else {
delete this;
}
}
void HandleMessageRead(const system::error_code& error,
size_t bytes_transferred) {
if(!error) {
cout << string(m_message, m_messageSize) << endl;
async_write(m_socket, buffer(&m_messageSize, sizeof(int)),
bind(&Session::HandleSizeWritten, this, placeholders::error));
} else {
delete this;
}
}
void HandleSizeWritten(const system::error_code& error) {
if(!error) {
async_write(m_socket, buffer(m_message, m_messageSize),
bind(&Session::HandleMessageWritten, this, placeholders::error));
} else {
delete this;
}
}
void HandleMessageWritten(const system::error_code& error) {
if(!error) {
delete m_message;
m_messageSizeIterator = reinterpret_cast<char*>(&m_messageSize);
async_read(m_socket, buffer(m_messageSizeIterator,
sizeof(m_messageSize)), bind(&Session::HandleSizeRead, this,
placeholders::error, placeholders::bytes_transferred));
} else {
delete this;
}
}
private:
tcp::socket m_socket;
int m_messageSize;
char* m_messageSizeIterator;
char* m_message;
};
class Server {
public:
Server(io_service& ioService, short port)
: m_ioService(ioService),
m_acceptor(ioService, tcp::endpoint(tcp::v4(), port)) {
Session* new_session = new Session(m_ioService);
m_acceptor.async_accept(new_session->GetSocket(), bind(&Server::HandleAccept,
this, new_session,asio::placeholders::error));
}
void HandleAccept(Session* new_session, const system::error_code& error) {
if(!error) {
new_session->StartRead();
new_session = new Session(m_ioService);
m_acceptor.async_accept(new_session->GetSocket(), bind(
&Server::HandleAccept, this, new_session, placeholders::error));
} else {
delete new_session;
}
}
private:
io_service& m_ioService;
tcp::acceptor m_acceptor;
};
int main(int argc, char* argv[]) {
try {
if(argc != 2) {
cerr << "Usage: server <port>\n";
return 1;
}
io_service io_service;
Server s(io_service, atoi(argv[1]));
io_service.run();
} catch(std::exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
И клиентский код выглядит следующим образом:
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
using namespace boost;
using namespace boost::asio;
using namespace boost::asio::ip;
using namespace std;
class Session {
public:
Session(io_service& ioService)
: m_socket(ioService) {}
tcp::socket& GetSocket() {
return m_socket;
}
void StartRead() {
m_messageSizeIterator = reinterpret_cast<char*>(&m_messageSize);
async_read(m_socket, buffer(m_messageSizeIterator, sizeof(m_messageSize)),
bind(&Session::HandleSizeRead, this, placeholders::error,
placeholders::bytes_transferred));
}
void StartWrite(const char* message, int messageSize) {
m_messageSize = messageSize;
m_message = new char[m_messageSize];
memcpy(m_message, message, m_messageSize);
async_write(m_socket, buffer(&m_messageSize, sizeof(int)),
bind(&Session::HandleSizeWritten, this, placeholders::error));
}
void HandleSizeRead(const system::error_code& error,
size_t bytes_transferred) {
if(!error) {
m_message = new char[m_messageSize];
async_read(m_socket, buffer(m_message, m_messageSize),
bind(&Session::HandleMessageRead, this, placeholders::error,
placeholders::bytes_transferred));
} else {
delete this;
}
}
void HandleMessageRead(const system::error_code& error,
size_t bytes_transferred) {
if(!error) {
cout << string(m_message, m_messageSize) << endl;
async_write(m_socket, buffer(&m_messageSize, sizeof(int)),
bind(&Session::HandleSizeWritten, this, placeholders::error));
} else {
delete this;
}
}
void HandleSizeWritten(const system::error_code& error) {
if(!error) {
async_write(m_socket, buffer(m_message, m_messageSize),
bind(&Session::HandleMessageWritten, this, placeholders::error));
} else {
delete this;
}
}
void HandleMessageWritten(const system::error_code& error) {
if(!error) {
delete m_message;
m_messageSizeIterator = reinterpret_cast<char*>(&m_messageSize);
async_read(m_socket, buffer(m_messageSizeIterator,
sizeof(m_messageSize)), bind(&Session::HandleSizeRead, this,
placeholders::error, placeholders::bytes_transferred));
} else {
delete this;
}
}
private:
tcp::socket m_socket;
int m_messageSize;
char* m_messageSizeIterator;
char* m_message;
};
int main(int argc, char* argv[]) {
try {
if(argc != 3) {
cerr << "Usage: client <host> <port>\n";
return 1;
}
io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), argv[1], argv[2]);
tcp::resolver::iterator iterator = resolver.resolve(query);
Session session(io_service);
tcp::socket& s = session.GetSocket();
s.connect(*iterator);
cout << "Enter message: ";
const int MAX_LENGTH = 1024;
char request[MAX_LENGTH];
cin.getline(request, MAX_LENGTH);
int requestLength = strlen(request);
session.StartWrite(request, requestLength);
io_service.run();
} catch (std::exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Любая помощь будет оценена, спасибо.
Для моих целей, посылая действительно очень маленькие сообщения и желая виртуальные ответы в режиме реального времени, отключение алгоритма Нэгла оказался причиной плохой работы.
Вы исключили возможности того, что может сделать ваш маршрутизатор, что вызывает проблему? Каково использование ЦП, как на каждой машине? – bobber205
Использование ЦП на обеих машинах равно 0. Что касается маршрутизатора, являющегося проблемой, я написал аналогичную программу без использования ASIO, и она работала очень быстро. – Kranar
Начните с тестирования вашей ссылки с помощью iperf. Затем инструмент весь процесс - создан ли сокет? Успешно ли связывание? Помогло ли решение? Работало ли подключение к серверу? Работала первая отправка? Работает ли первая работа? Вызывает ли какой-либо вызов API сети какие-либо ошибки? Что-нибудь дольше, чем ожидалось? Посмотрите на сетевой трафик. Есть ли межсетевой экран на сервере? Включен ли алгоритм Nagle? Серверу потребовалось много времени, чтобы ответить? Есть ли какая-то задержка, которую вы не ожидали в несетевом коде в клиенте? – Permaquid