Я пытаюсь реализовать простое клиент-серверное приложение, в котором я представлю простой API для клиента, чтобы взаимодействовать с сервером. Проблема в том, что когда я пытаюсь использовать этот API, клиент жалуется на ошибку system:32
, которая означает сломанную трубу. Однако, если я вызываю функцию изнутри класса, все работает безупречно.Boost Asio: сломанная труба при попытке вызвать функцию записи «externaly»
#include <boost/bind.hpp>
#include <cstdio> /* sprintf */
#include "client.hpp"
#include "commands.hpp"
Client::Client(boost::asio::io_service& io_service,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator):
io_service_(io_service),
socket_(io_service)
{
boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
boost::bind(&Client::handle_connect, this, endpoint_iterator,
boost::asio::placeholders::error
)
);
}
void Client::handle_connect(boost::asio::ip::tcp::resolver::iterator
endpoint_iterator, const boost::system::error_code& error)
{
if(!error)
{
//Client::read_header(read_.header(), read_.header_length());
Client::identify_user("User", "Password");
}
else if(endpoint_iterator != boost::asio::ip::tcp::resolver::iterator())
{
socket_.close();
boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
socket_.async_connect(endpoint,
boost::bind(&Client::handle_connect, this, ++endpoint_iterator,
boost::asio::placeholders::error
)
);
}
}
void Client::handle_readheader(size_t bytes_transferred,
const boost::system::error_code& error)
{
if(bytes_transferred)
{
if(read_.decode_command() == IDENTIFY)
{
Client::identify_user("Username", "Password");
}
}
else
{
Client::read_header(read_.header(), read_.header_length());
}
}
void Client::handle_read(size_t bytes_transferred,
const boost::system::error_code& error)
{
if(bytes_transferred)
{
Client::read_header(read_.header(), read_.header_length());
}
else if(error)
{
}
else
{
Client::read_header(read_.header(), read_.header_length());
}
}
void Client::handle_write(size_t bytes_transferred,
const boost::system::error_code& error)
{
if(bytes_transferred)
{
Client::read_header(read_.header(), read_.header_length());
}
else if(error)
{
}
else
{
Client::read_header(read_.header(), read_.header_length());
}
}
void Client::handle_writeheader(size_t bytes_transferred,
const boost::system::error_code& error)
{
if(bytes_transferred)
{
if(write_.decode_command() == AUTHENTICATE)
{
std::cout << "Bodylen:" << write_.decode_size() << std::endl;
std::cout << write_.body() << std::endl;
Client::write(write_.body(), write_.decode_size());
}
}
else if(error)
{
std::cout << "Error HWH: " << error << std::endl;
}
else
{
Client::read_header(read_.header(), read_.header_length());
}
}
void Client::identify_user(const char* username, const char* password)
{
size_t tmplen = (strlen(username) + strlen(password) + 2);
char tmpbody[tmplen];
std::sprintf(tmpbody, "%s:%s", username, password);
write_.body(tmpbody);
std::cout << write_.body() << std::endl;
write_.encode_header(11, tmplen);
std::cout << write_.header() << std::endl;
Client::write_header(write_.header(), write_.header_length());
}
void Client::read(char* buffer, size_t len)
{
boost::asio::async_read(socket_, boost::asio::buffer(buffer, len),
boost::bind(&Client::handle_read, this,
boost::asio::placeholders::bytes_transferred,
boost::asio::placeholders::error
)
);
}
void Client::read_header(char* buffer, size_t len)
{
boost::asio::async_read(socket_, boost::asio::buffer(buffer, len),
boost::bind(&Client::handle_readheader, this,
boost::asio::placeholders::bytes_transferred,
boost::asio::placeholders::error
)
);
}
void Client::write_header(char* buffer, size_t len)
{
boost::asio::async_write(socket_, boost::asio::buffer(buffer, len),
boost::bind(&Client::handle_writeheader, this,
boost::asio::placeholders::bytes_transferred,
boost::asio::placeholders::error
)
);
}
void Client::write(char* buffer, size_t len)
{
boost::asio::async_write(socket_, boost::asio::buffer(buffer, len),
boost::bind(&Client::handle_write, this,
boost::asio::placeholders::bytes_transferred,
boost::asio::placeholders::error
)
);
}
int main(){
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver(io_service);
boost::asio::ip::tcp::resolver::query query("localhost", "5000");
boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query);
Client client(io_service, iterator);
//client.identify_user("User", "Password");
io_service.run();
return(0);
}
В теории, поведение должно быть следующее: клиент посылает заголовок аутентификации на сервере - через identify_client - с указанием количества байтов, чтобы быть отправленными после этого, и ждет, пока он не получит ACK - вызов read_header (...) -. Сервер отправляет подтверждение ACK, которое готово обрабатывать все, что отправляет клиент. Клиент отправляет пользователя и пароль.
Однако, как я сказал выше, он работает только, когда я звоню identify_client
через handle_connect
, что совершенно бесполезно и статично. Что я делаю не так?
спасибо, что заранее.
EDIT: Класс сообщения просто класс очень похож на this one, что помогает мне манипулировать и легко интерпретировать сообщения Протокола.
EDIT2: Я попытаюсь объяснить это немного лучше. Я считаю функцию main
«вне класса», как нечто независимое. Затем функция main
создает объект Client
, который содержит API для отправки и получения данных с сервера. Я прикрепляю файл .hpp, надеясь, что это поможет вам лучше понять.
Поэтому, если у меня был цикл, как следующий один ...
/* ... */
for(;;)
{
/* ... */
// Do something here
/* If a condition, then authenticate the user */
//client.identify_user("User", "Password");
// Do something there
/* ... */
}
/* ... */
... используя этот созданный объект, я должен быть в состоянии назвать конкретные функции члена объекта, который будет инициировать дальнейшие операции записи или читает. Проблема, которую я имею прямо сейчас, заключается в том, что я не могу этого добиться.
Если я звоню identify_user
от handle_connect(...)
функция класса Client
-а показан в исходном коде выше, он работает. Но, конечно, я не могу достичь того, чего хочу.
Если я прокомментирую это, чтобы вызвать функцию из main
, я получаю сообщение об ошибке разбитого трубопровода.
if(!error)
{
//Client::read_header(read_.header(), read_.header_length());
//Client::identify_user("User", "Password");
}
Если я оставлю код, как это, я получаю ту же ошибку обрыва трубы.
if(!error)
{
Client::read_header(read_.header(), read_.header_length());
//Client::identify_user("User", "Password");
}
Когда я узнавал о ASIO, я прочитал, что если io_service исчерпывает работы, то отделки приложений. Может быть, моя проблема имеет какое-то отношение к этому.
EDIT4: Я люблю говорить, что я собираюсь приложить что-то и полностью забыть об этом.
#ifndef CLIENT_HPP
#define CLIENT_HPP
#include <boost/asio.hpp>
#include "message.hpp"
class Client
{
public:
Client(boost::asio::io_service& io_service,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
void identify_user(const char* username, const char* password);
private:
void handle_connect(
boost::asio::ip::tcp::resolver::iterator endpoint_iterator,
const boost::system::error_code& error);
void handle_read(size_t bytes_transferred,
const boost::system::error_code& error);
void handle_readheader(size_t bytes_transferred,
const boost::system::error_code& error);
void handle_write(size_t bytes_transferred,
const boost::system::error_code& error);
void handle_writeheader(size_t bytes_transferred,
const boost::system::error_code& error);
void read(char* buffer, size_t len);
void read_header(char* buffer, size_t len);
void write_header(char* buffer, size_t len);
void write(char* buffer, size_t len);
boost::asio::io_service& io_service_;
boost::asio::ip::tcp::socket socket_;
Message read_;
Message write_;
};
#endif /* client.hpp */
Edit5: Это, кажется, сделать трюк. Это было определенно что-то делать с io_service:
for(;;)
{
io_service.poll();
client.identify_user("User", "Password");
}
Я не знаю, что вы подразумеваете под «изнутри класса». Весь этот код выполняется внутри класса. – EJP
@EJP Я добавил некоторую информацию, но, возможно, мне просто становится все труднее понять. – MikelAlejoBR