// 设置异步接收数据
bind_hand_read(m_nextClient.get());
// 将客户端连接放到客户表中
m_clients.insert(make_pair(m_nextClient->m_clientId, m_nextClient));
// 重置下一个客户端连接
m_nextClient = make_shared<CTcpConnection>(m_ioservice, m_clientId);
m_clientId++;
}
}
// 异步等待下一个客户端连接
m_acceptor.async_accept(m_nextClient->m_socket, boost::bind(&CAsyncTcpServer::handle_accept, this, boost::asio::placeholders::error));
}
void CAsyncTcpServer::bind_hand_read(CTcpConnection* client)
{
client->m_socket.async_read_some(boost::asio::buffer(client->m_buffer),
boost::bind(&CAsyncTcpServer::handle_read, this, client, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
return;
client->m_socket.async_receive(boost::asio::buffer(client->m_buffer),
boost::bind(&CAsyncTcpServer::handle_read, this, client, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
boost::asio::async_read(client->m_socket, boost::asio::buffer(client->m_buffer),
boost::bind(&CAsyncTcpServer::handle_read, this, client, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
}
void CAsyncTcpServer::handle_read(CTcpConnection* client, const boost::system::error_code& error, size_t bytes_transferred)
{
if (!error)
{
// 发送收到数据的信息
for (int i = 0; i < m_EventHandlers.size(); ++i)
{
m_EventHandlers[i]->ReceiveData(client->m_clientId, client->m_buffer.data(), bytes_transferred);
}
bind_hand_read(client);
}
else
{
// 发送客户端离线的消息
for (int i = 0; i < m_EventHandlers.size(); ++i)
{
m_EventHandlers[i]->ClientDisconnect(client->m_clientId);
}
m_clients.erase(client->m_clientId);
}
}
AsyncTcpServer 类调用
服务端首先定义CEventHandler
类并继承自CAsyncTcpServer::IEventHandler
接口,该类内需要我们实现三个方法,方法ClientConnected
用于在客户端连接时触发,方法ClientDisconnect
则是在登录客户端离开时触发,而当客户端有数据发送过来时则ReceiveData
方法则会被触发。
方法ClientConnected
当被触发时自动将clientId
客户端Socket套接字放入到tcp_client_id
全局容器内存储起来,而当ClientDisconnect
客户端退出时,则直接遍历这个迭代容器,找到序列号并通过tcp_client_id.erase
将其剔除;
// 客户端连接时触发
virtual void ClientConnected(int clientId)
{
// 将登录客户端加入到容器中
tcp_client_id.push_back(clientId);
}
// 客户端退出时触发
virtual void ClientDisconnect(int clientId)
{
// 将登出的客户端从容器中移除
vector<int>::iterator item = find(tcp_client_id.begin(), tcp_client_id.end(), clientId);
if (item != tcp_client_id.cend())
tcp_client_id.erase(item);
}
而ReceiveData
一旦收到数据,则直接将其打印输出到屏幕,即可实现客户端参数接收的目的;
// 客户端获取数据
virtual void ReceiveData(int clientId, const BYTE* data, size_t length)
{
std::cout << std::endl;
PrintLine(80);
std::cout << data << std::endl;
PrintLine(80);
std::cout << "[Shell] # ";
}
相对于接收数据而言,发送数据则是通过同步的方式进行,当我们需要发送数据时,只需要将数据字符串放入到一个BYTE*
字节数组中,并在调用tcpServer.Send
时将所需参数,套接字ID,缓冲区Buf数据,以及长度传递即可实现将数据发送给指定的客户端;
// 同步发送数据到指定的线程中
void send_message(CAsyncTcpServer& tcpServer, int clientId, std::string message, int message_size)
{
// 获取长度
BYTE* buf = new BYTE(message_size + 1);
memset(buf, 0, message_size + 1);
for (int i = 0; i < message_size; i++)
{
buf[i] = message.at(i