#include <asio2/asio2.hpp>
int main()
{
std::string_view host = "0.0.0.0";
std::string_view port = "8028";
asio2::tcp_server server;
server.bind_init([]()
{
// 第1步:触发init回调函数
// 当监听socket打开成功(即socket(AF_INET, SOCK_STREAM, 0)函数调用结束)之后,这里被触发。
// 这个函数只会在服务端启动时触发1次。
// 可以在这里给监听socket设置一些选项什么的。
}).bind_start([&]()
{
// 第2步:触发start回调函数
// 当监听socket监听成功(即bind,listen函数调用结束)之后,这里被触发。
// 这个函数只会在服务端启动时触发1次。
// 可以在这里记录服务端启动成功的日志。
printf("start tcp server : %s %u\n",
server.listen_address().c_str(), server.listen_port());
}).bind_accept([](std::shared_ptr<asio2::tcp_session>& session_ptr)
{
// 第3步:触发accept回调函数
// 当某个客户端刚连接上服务端之后,这里被触发。
// 这个函数会多次触发,每有1个客户端连接上来之后,就会触发1次。但1个客户端只
// 触发1次。由于客户端有掉线自动重连机制,所以客户端每重连1次,就会触发1次。
// 可以在这里判断该客户端是不是在黑名单中,如果是,直接调用stop将该客户端断开。
// 此时还不能给这个客户端发送数据,会由于连接还未完全建立而导致发送失败。
if (session_ptr->remote_address() == "192.168.1.100")
session_ptr->stop();
}).bind_connect([&](auto & session_ptr)
{
// 第4步:触发connect回调函数
// 当某个客户端和服务端的连接完全建立成功之后,这里被触发。
// 这个函数会多次触发,每有1个客户端连接完成之后,就会触发1次。但1个客户端只
// 触发1次。
// 可以在这里给该客户端发送数据了。
// 可能有人会问,对于tcp来说,只要连接建立了,不就立即可以发数据了吗?为什么在上面的
// bind_accept中不能发,在这里的bind_connect中才能发呢?
// 这是因为asio2框架人为的给这个连接做了一个状态标识(status),在bind_accept中该status
// 是starting,表示连接还未完全建立,当触发到bind_connect时才会给该连接的状态标识设置
// 为started,表示连接建立全部完成了。所以如果在bind_accept中发送数据的话,框架会判断
// 到状态标识不是started所以就不允许发送数据。
// 那为什么要做这样一个状态标识呢?
// 因为对于ssl来说,连接建立之后,还有ssl握手,只有ssl握手成功以后才能收发数据。对于
// websocket来说,连接建立之后,还有upgrade升级协商,只有upgrade升级之后才能收发数据,
// 所以为了整体框架流程统一,人为的做了一个规定,只有触发了bind_connect的回调函数之后
// 才表示整个连接完全建立结束了。
session_ptr->no_delay(true);
printf("client enter : %s %u %s %u\n",
session_ptr->remote_address().c_str(), session_ptr->remote_port(),
session_ptr->local_address().c_str(), session_ptr->local_port());
}).bind_recv([&](std::shared_ptr<asio2::tcp_session> & session_ptr, std::string_view data)
{
// 第5步:触发recv回调函数
// 当收到某个客户端发送过来的数据之后,这里被触发。
// 这个函数会多次触发,每有1个客户端发送数据过来之后,就会触发1次。且1个客户端也会
// 触发多次,即发送数据就触发1次。
// 在这里对接收到的数据进行解析处理。
printf("recv : %u %.*s\n", (unsigned)data.size(), (int)data.size(), data.data());
session_ptr->async_send(data, [](std::size_t bytes_sent) {});
}).bind_disconnect([&](auto & session_ptr)
{
// 第6步:触发disconnect回调函数
// 当某个客户端关闭了,服务端收到该客户端的连接断开事件之后,
// 在该连接对应的socket关闭之前(即closesocket函数调用之前),这里被触发。
// 这个函数会多次触发,每有1个客户端连接完成之后,就会触发1次。但1个客户端只
// 触发1次。
// 可以在这里记录客户端的断开日志。
printf("client leave : %s %u %s\n",
session_ptr->remote_address().c_str(),
session_ptr->remote_port(), asio2::last_error_msg().c_str());
}).bind_stop([&]()
{
// 第7步:触发stop回调函数
// 当关闭服务端时,在所有的连接都全部断开了之后,在监听socket关闭之前,这里被触发。
// 注意:必须所有连接全部断开了,且所有的session_ptr的引用计数为0了,这里才会触发,
// 因此如果你将session_ptr保存在了其它地方,一定要记得将你保存的session_ptr删除,
// 否则server.stop()函数会一直阻塞无法结束,这里的回调函数也无法触发。
// 这个函数只会在服务端关闭时触发1次。
// 可以在这里记录服务端的停止日志。
printf("stop tcp server : %d %s\n", asio2::last_error_val(), asio2::last_error_msg().c_str());
});
server.start(host, port);
while (std::getchar() != '\n'); // press enter to exit this program
server.stop();
return 0;
}
#include <asio2/asio2.hpp>
int main()
{
std::string_view host = "127.0.0.1";
std::string_view port = "8028";
asio2::tcp_client client;
client.bind_init([]()
{
// 第1步:触发init回调函数
// 当客户端socket打开成功(即socket(AF_INET, SOCK_STREAM, 0)函数调用结束)之后,这里被触发。
// 这个函数只会在客户端启动时触发1次。
// 可以在这里给socket设置一些选项什么的。
}).bind_connect([&]()
{
// 第2步:触发connect回调函数
// 当客户端连接服务端完成之后,这里被触发。
// 这个函数只会在客户端连接服务端时触发1次,不管连接成功还是连接失败都会触发。连接
// 成功还是失败,可以使用asio2::get_last_error()来进行判断。
// 注意:客户端有掉线自动重连机制,因此,如果客户端连接服务端失败,那么客户端过几秒后
// 会再次自动连接服务端,每连接一次服务端,不管连接成功还是失败,此函数就会被触发1次。
// 可以在这里给向服务端发送数据了。
if (asio2::get_last_error())
printf("connect failure : %d %s\n", asio2::last_error_val(), asio2::last_error_msg().c_str());
else
printf("connect success : %s %u\n", client.local_address().c_str(), client.local_port());
// 如果没有错误,就表示连接成功,可以向服务端发送数据了。
if (!asio2::get_last_error())
client.async_send("<abcdefghijklmnopqrstovuxyz0123456789>");
}).bind_recv([&](std::string_view data)
{
// 第3步:触发recv回调函数
// 当收到服务端发送过来的数据之后,这里被触发。
// 这个函数会多次触发,每接收到1次数据,就会触发1次。
// 可以在这里对接收到的数据进行解析处理。
printf("recv : %u %.*s\n", (unsigned)data.size(), (int)data.size(), data.data());
client.async_send(data);
}).bind_disconnect([&]()
{
// 第4步:触发disconnect回调函数
// 当客户端关闭时(或者服务端关闭了),在socket即将关闭之前,这里被触发。
// 这个函数只会在客户端关闭时触发1次。且只有在客户端连接成功之后才会被触发,就是
// 说如果客户端没有成功连接上服务端,那么客户端在关闭时是不会触发disconnect的。
// 可以在这里记录客户端的关闭日志。
printf("disconnect : %d %s\n", asio2::last_error_val(), asio2::last_error_msg().c_str());
});
client.start(host, port);
while (std::getchar() != '\n');
return 0;
}
#include <asio2/asio2.hpp>
int main()
{
std::string_view host = "0.0.0.0";
std::string_view port = "8028";
asio2::tcp_server server;
server.bind_recv([&](std::shared_ptr<asio2::tcp_session> & session_ptr, std::string_view data)
{
printf("recv : %u %.*s\n", (unsigned)data.size(), (int)data.size(), data.data());
session_ptr->async_send(data, [](std::size_t bytes_sent) {});
});
server.start(host, port);
while (std::getchar() != '\n'); // press enter to exit this program
server.stop();
return 0;
}
github : https://github.com/zhllxt/asio2
码云 : https://gitee.com/zhllxt/asio2