我如何创建一个Boost.Asio服务器,可以同时处理多个客户端
How do I create a Boost.Asio Server that can handle multiple clients at once?
我可以创建一个可以响应一个客户机的简单TCP服务器,但是我不知道如何创建一个可以同时处理多个客户机的服务器。我已经提到的例子,如TCP日间异步服务器,但它只是发送数据到客户端。我需要创建的是只要客户端存在,连接就保持活跃。客户端和服务器都将使用Json进行通信。考虑一种情况,客户端将给出{"hello":"Client"}
,服务器应该响应{"Hello":"Server"}
,并且说另一个{"message":"How are you?"}
和它的响应{"response" : "Fine"}
。我需要同时处理多个客户。我读了聊天服务器文档,但它太难理解了。有人能给出如何使用Boost.Asio启动代码的基本流程吗?谢谢。
下面是给出的代码:
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include <json/reader.h>
#include <json/writer.h>
Json::Value GetRootFromJson(std::string json)
{
Json::Value root;
Json::Reader reader;
bool success = reader.parse(json, root);
return root;
}
std::string GetJsonFromRoot(Json::Value root)
{
Json::FastWriter writer;
std::string json = writer.write(root);
return json;
}
using boost::asio::ip::tcp;
std::string make_daytime_string()
{
using namespace std; // For time_t, time and ctime;
time_t now = time(0);
return ctime(&now);
}
class tcp_connection
: public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
//message_ = make_daytime_string();
//Read from client, make json and send appropriate response
boost::asio::async_read(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
std::string messageP(message_);
std::cout << messageP << std::endl;
Json::Value root = GetRootFromJson(messageP);
std::string isHello = root["hello"].asString();
std::string isMessage = root["message"].asString();
if(!isHello.empty())
{
std::string messageTemp = "{"Hello":"Server"}";
boost::asio::async_write(socket_, boost::asio::buffer(messageTemp),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
if(!isMessage.empty())
{
std::string messageTemp = "{"response":"Fine"}";
boost::asio::async_write(socket_, boost::asio::buffer(messageTemp),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
/*
boost::asio::async_write(socket_, boost::asio::buffer(message_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
*/
}
private:
tcp_connection(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
void handle_write(const boost::system::error_code& /*error*/,
size_t /*bytes_transferred*/)
{
}
void handle_read(const boost::system::error_code& /*error*/,
size_t /*bytes_transferred*/)
{
std::cout << "Handle Read of connectionn";
}
tcp::socket socket_;
std::string message_;
};
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 1936))
{
start_accept();
}
private:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
std::cout << "A client connected" << std::endl;
new_connection->start();
}
start_accept();
}
tcp::acceptor acceptor_;
};
int main()
{
try
{
boost::asio::io_service io_service;
tcp_server server(io_service);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
错误2错误C2679: binary '=':找不到右操作数类型为'const boost::asio::const_buffer'(或没有可接受的转换)C:boost_1_55_0_dynboostasiodetailconsuming_buffers.hpp 175
编辑:我添加了一个非常简单的客户端代码,它将发送"{"Hello":"Client"}"
到服务器并期望输出。但是由sehe给出的服务器代码不能进入handle_read
#include <iostream>
#include <boost/array.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
int main(int argc, char* argv[])
{
try
{
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query("localhost", "1936");
tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
tcp::socket socket(io_service);
boost::asio::connect(socket, endpoint_iterator);
std::string message = "{"hello":"Client"}";
std::cout << "Sending the message: " << message << std::endl;
socket.send(boost::asio::buffer(message));
std::cout << "Sent the message: " << message << std::endl;
boost::asio::streambuf buf;
size_t len;
std::string messageReceived;
boost::asio::streambuf::mutable_buffers_type mbuf = buf.prepare(512);
std::cout << "Now receiving messagen";
std::string messageServer;
try
{
boost::asio::streambuf buf;
size_t len;
boost::asio::streambuf::mutable_buffers_type mbuf = buf.prepare(512);
do {
len = socket.receive(mbuf);
std::cout << len << std::endl;
std::string str(boost::asio::buffers_begin(mbuf), boost::asio::buffers_begin(mbuf) + len);
messageServer = messageServer + str;
} while (len>=512);
}
catch (boost::system::system_error err)
{
std::cout << err.code() << " " << err.what();
}
std::cout << messageServer << std::endl;
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
这是实现服务器的正确方法吗?谢谢你。
如文档所述,
boost::asio::async_read(socket_, boost::asio::buffer(message_),
接受一个流函数
此外,它是一个异步操作,因此在发布读操作之后,在调用完成处理程序(handle_read
)之前访问message_
0 是有意义的。
我至少可以编译以下代码:
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include <json/reader.h>
#include <json/writer.h>
namespace {
Json::Value to_json(std::string json)
{
Json::Value root;
Json::Reader reader;
/*bool success =*/ reader.parse(json, root);
return root;
}
std::string to_string(Json::Value root) // unused TODO FIXME
{
Json::FastWriter writer;
std::string json = writer.write(root);
return json;
}
}
using boost::asio::ip::tcp;
class tcp_connection : public boost::enable_shared_from_this<tcp_connection>
{
public:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
tcp::socket& socket()
{
return socket_;
}
void start()
{
//Read from client, make json and send appropriate response
boost::asio::async_read(socket_, message_,
boost::bind(&tcp_connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
private:
tcp_connection(boost::asio::io_service& io_service)
: socket_(io_service)
{
}
void handle_write(const boost::system::error_code& /*error*/,
size_t /*bytes_transferred*/)
{
}
void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
{
std::cout << "Handle Read of connectionn";
if (error && error != boost::asio::error::eof) {
std::cout << "Error: " << error.message() << "n";
return;
}
std::string messageP;
{
std::stringstream ss;
ss << &message_;
ss.flush();
messageP = ss.str();
}
std::cout << messageP << std::endl;
Json::Value root = to_json(messageP);
std::string isHello = root["hello"].asString();
std::string isMessage = root["message"].asString();
if(!isHello.empty())
{
std::string messageTemp = "{"Hello":"Server"}";
boost::asio::async_write(socket_, boost::asio::buffer(messageTemp),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
if(!isMessage.empty())
{
std::string messageTemp = "{"response":"Fine"}";
boost::asio::async_write(socket_, boost::asio::buffer(messageTemp),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
tcp::socket socket_;
boost::asio::streambuf message_;
};
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 1936))
{
start_accept();
}
private:
void start_accept()
{
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
}
void handle_accept(tcp_connection::pointer new_connection, const boost::system::error_code& error)
{
if (!error)
{
std::cout << "A client connected" << std::endl;
new_connection->start();
}
start_accept();
}
tcp::acceptor acceptor_;
};
int main()
{
try
{
boost::asio::io_service io_service;
tcp_server server(io_service);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
}
您需要的包含。有些可能是不必要的:
boost/asio.hpp
, boost/thread.hpp
, boost/asio/io_service.hpp
boost/asio/spawn.hpp
, boost/asio/write.hpp
, boost/asio/buffer.hpp
boost/asio/ip/tcp.hpp
, iostream
, stdlib.h
, array
, string
vector
, string.h
, stdio.h
, process.h
, iterator
using namespace boost::asio;
using namespace boost::asio::ip;
io_service ioservice;
tcp::endpoint sim_endpoint{ tcp::v4(), 4066 }; //{which connectiontype, portnumber}
tcp::acceptor sim_acceptor{ ioservice, sim_endpoint };
std::vector<tcp::socket> sim_sockets;
static int iErgebnis;
int iSocket = 0;
void do_write(int a) //gets the postion of the socket in the vector
{
int iWSchleife = 1; //to stay connected with putty or something
static char chData[32000];
std::string sBuf = "Received!rn";
while (iWSchleife > 0)
{
boost::system::error_code error;
memset(chData, 0, sizeof(chData));
iErgebnis = sim_sockets[a].read_some(boost::asio::buffer(chData), error); //recv wie bei winsock. simulator empfängt
iWSchleife = iErgebnis; //if iErgebnis is bigger then 0 it will stay in the loop. iErgebniss is always >0 when data is received
if (iErgebnis > 0) {
printf("%d Zeichen empf.vom Client : n%snn", iErgebnis, chData);
write(sim_sockets[a], boost::asio::buffer(sBuf), error);
}
else {
boost::system::error_code ec;
sim_sockets[a].shutdown(boost::asio::ip::tcp::socket::shutdown_send, ec); //close the socket when no data
if (ec)
{
printf("studown error"); // An error occurred.
}
}
}
}
void do_accept(yield_context yield)
{
while (1) //endless loop to accept limitless clients
{
sim_sockets.emplace_back(ioservice); //look to the link below for more info
sim_acceptor.async_accept(sim_sockets.back(), yield); //waits here to accept an client
boost::thread dosome(do_write, iSocket); //when accepts starts the thread do_write and passes the parameter iSocket
iSocket++; //to know the position of the socket in the vector
}
}
int main()
{
sim_acceptor.listen();
spawn(ioservice, do_accept); //here you can learn more about Coroutines https://theboostcpplibraries.com/boost.coroutine
ioservice.run(); //from here you jump to do:accept
getchar();
}
- 提升 Asio TCP 服务器 处理多个客户端
- 如何使用 winsock32 处理多客户端
- 如何处理在 CPP 中连接到服务器的多个客户端?
- VC++ 异常处理在 x86 和 x64 上对于 IBPP / Firebird 客户端有所不同
- 从QT Web服务器处理多个客户端
- ZeroMQ REQ/REP如何处理多个客户端
- 使用ACE_dll动态加载客户端C++dll,错误为未处理的异常
- 当函数有很多参数和客户端代码只需更改其中时,如何处理情况就可以处理
- 在C++winsock中处理多个客户端的方法
- 多线程服务器在一个线程中处理多个客户端
- 处理客户端连接的最有效方法(套接字编程)
- c++tcp多线程客户端/服务器-如何与线程套接字处理程序进行通信
- 在Windows下处理多个客户端连接的最佳方法(不使用线程)
- 加速和 Windows 套接字 - 正确处理 TCP 客户端断开连接方案
- 客户端类构造函数中未处理的提升解析调用
- 改进服务器以处理多个客户端
- Thrift Java 客户端无法正确处理联合
- 用于处理许多客户端 c++ 的分叉服务器
- C++自定义客户端处理程序
- 如何使用SOAP处理多个客户端