В настоящее время я пытаюсь создать соединение между сервером и клиентом для отправки XML-документов. Представляется, что эти документы можно отправить после их сериализации. Мой план состоит в том, чтобы установить соединение, отправить одно сообщение от клиента на сервер (список фильтров), а затем отправить N сообщений со стороны сервера, когда сообщение соответствует критериям фильтров.
Однако, прежде чем перейти к этому, я хотел попробовать простую реализацию этого, используя только строки, чтобы увидеть, как это работает, и лучше понять библиотеку boost asio.
Затем я реализовал свою серверную часть:
#include <iostream>
#include <thread>
#include <queue>
#include <chrono>
#include <array>
#include <boost/asio.hpp>
int main()
{
const int BACKLOG_SIZE = 30;
unsigned short PORT = 3333;
// Endpoint and io_service creation
boost::asio::ip::tcp::endpoint ep(boost::asio::ip::address_v4::any(),PORT);
boost::asio::io_service ios;
boost::asio::ip::tcp::acceptor acceptor(ios, ep.protocol());
// Binding to client
acceptor.bind(ep);
acceptor.listen(BACKLOG_SIZE);
boost::asio::ip::tcp::socket socket(ios);
// accepting connection (blocking process)
acceptor.accept(socket);
std::cout << "Binded" << std::endl;
// Receiving data from client
boost::asio::streambuf sb;
boost::system::error_code ec;
while (boost::asio::read(socket, sb, ec))
{
std::cout << "received: " << &sb << "\n";
if (ec)
{
std::cout << "status: " << ec.message() << "\n";
break;
}
}
// Sending data to client
socket.send("Filters received!");
}
и моя клиентская часть:
#include <boost/asio.hpp>
#include <iostream>
int main()
{
std::string raw_ip_address = "127.0.0.1";
unsigned short port_num = 3333;
std::string FILTER = "ATL";
try {
// Endpoint creation
boost::asio::ip::tcp::endpoint
ep(boost::asio::ip::address::from_string(raw_ip_address),
port_num);
boost::asio::io_service ios;
// Creating and opening a socket.
boost::asio::ip::tcp::socket sock(ios, ep.protocol());
// Connecting a socket.
sock.connect(ep);
// Sending data to server
std::cout << "Connected to " << raw_ip_address << " Port: " << port_num << std::endl;
sock.send(boost::asio::buffer(FILTER));
boost::asio::streambuf sb;
boost::system::error_code ec;
// Receiving data from server
while (boost::asio::read(socket, sb, ec))
{
std::cout << "received: " << &sb << "\n";
if (ec)
{
std::cout << "status: " << ec.message() << "\n";
break;
}
}
}
// Overloads of asio::ip::address::from_string() and
// asio::ip::tcp::socket::connect() used here throw
// exceptions in case of error condition.
catch (boost::system::system_error& e) {
std::cout << "Error occured! Error code = " << e.code()
<< ". Message: " << e.what();
return e.code().value();
}
return 0;
}
Сначала я начал только с отправки фильтров с клиента на сервер, и все это работало хорошо. Однако, когда я попытался добавить ответ от сервера к клиенту, это вызвало ошибку, которую я действительно не понимаю: ошибка
Кто сталкивался с этой проблемой и знает как ее решить? Возможно ли вообще установить такое соединение, при котором обе стороны сокета могут отправлять сообщения по своему усмотрению (как я уже сказал, идея будет заключаться в том, чтобы сервер отправлял N сообщений из другого приложения после получения списка фильтров).
Спасибо за вашу помощь.





Первая проблема: строковые литералы не являются буфером (или буферной последовательностью).
Вам нужно описать буфер, например. вот так:
std::string response("Filters received!");
socket.send(boost::asio::buffer(response));
Есть много способов. Например. не используя временный, вы можете использовать литерал представления строки:
socket.send(boost::asio::buffer("Filters received!"sv));
Вторая проблема:
while (boost::asio::read(socket, sb, ec)) {
Это не может работать, потому что вы имели в виду sock, а не socket (который существует, но есть ::socket, введите int(&)(int,int,int).
Тем не менее, чтение в EOF в цикле while не очень полезно, так как цикл всегда прерывается из-за EOF (или другой ошибки).
Наконец, поскольку в настоящее время клиент никогда не закроет сокет, пока не будет получен ответ, будет неопределенное ожидание обеих программ. Рассмотрим частичное отключение:
sock.send(asio::buffer(FILTER));
sock.shutdown(tcp::socket::shutdown_send);
Вот клиент и сервер вместе
#include <boost/asio.hpp>
#include <iostream>
namespace asio = boost::asio;
using asio::ip::tcp;
using boost::system::error_code;
using namespace std::string_view_literals;
static const std::string raw_ip_address = "127.0.0.1";
static const std::string FILTER = "ATL";
static const int BACKLOG_SIZE = 30;
static const uint16_t PORT = 3333;
int main(int argc, char**) {
asio::io_service ios;
asio::streambuf sb;
error_code ec;
try {
if (argc > 1) { // client
tcp::endpoint ep({}, PORT);
tcp::socket sock(ios, ep.protocol());
sock.connect(ep);
// Sending data to server
std::cout << "Connected to " << sock.remote_endpoint() << std::endl;
sock.send(asio::buffer(FILTER));
sock.shutdown(tcp::socket::shutdown_send);
read(sock, sb, ec);
std::cout << "received: " << &sb << "\n"
<< "status: " << ec.message() << "\n";
} else // server
{
tcp::acceptor acceptor(ios, tcp::v4());
acceptor.bind({{}, PORT});
acceptor.listen(BACKLOG_SIZE);
tcp::socket sock(ios);
acceptor.accept(sock);
std::cout << "Accepted " << sock.remote_endpoint() << std::endl;
read(sock, sb, ec);
std::cout << "received: " << &sb << "\n"
<< "status: " << ec.message() << "\n";
sock.send(asio::buffer("Filters received!"sv));
}
} catch (boost::system::system_error& e) {
std::cout << "Error occured! Error code = " << e.code()
<< ". Message: " << e.what() << "\n";
return 1; // e.code().value() not very useful, as the category is lost
}
}
Запуск и сборка, например.
g++ -std=c++20 -O2 -Wall -pedantic -pthread main.cpp -isystem /usr/local/include/
./a.out&
sleep 1; ./a.out client
Отпечатки, например.
Connected to 127.0.0.1:3333
Accepted 127.0.0.1:50816
received: ATL
status: End of file
received: Filters received!
status: End of file
Спасибо, это решило мою проблему с отправкой обратных сообщений. Я разделил код, чтобы можно было запускать и сервер, и клиент на разных кодах. Однако без цикла while в функции чтения я не могу попросить клиентскую сторону ждать дополнительных сообщений от сервера. Идея этого асинхронного обмена сообщениями заключается в том, что клиент ожидает возможного сообщения от сервера и обрабатывает каждое из них индивидуально, когда оно доступно. Насколько я понимаю, даже если я отправлю 3 сообщения, все 3 будут получены клиентом в один и тот же момент. (Я исправил свой комментарий, чтобы быть более точным)
В любом случае вы не можете, потому что вы не определили «сообщение» - и ваше чтение никогда не завершается, пока отправляющая сторона не отключит соединение. Кроме того, ваш обмен сообщениями является синхронным.
Если вы хотите кадрирование, определите кадрирование. Например: coliru.stacked-crooked.com/a/95a8a52573f29dba
А вот и все асинхронно, с несколькими параллельными клиентами в одной программе: coliru.stacked-crooked.com/a/0cdb0ef5c6e0c542
Вы всегда должны публиковать ошибку в виде текста, а не изображения в stackoverflow.