asio kcp 代码走读
(1)kcp_client_wrap 类
a 提供方法接口如下:
- send_msg
- kcp_client_.send_msg(msg);
- stop // 等待工作线程退出
- set_event_callback
- connect //main 函数中调用 connect 进行 kcp client 的初始化
- kcp_client_.connect_async
- do_asio_kcp_connect_loop
- connect_async
- connect_result
b 包含的私有方法:
- start_workthread
- client_event_callback_func
- handle_client_event_callback
- do_asio_kcp_connect_loop
- while(){kcp_client_.update();} // 主线程中 kcp 的 tick
- workthread_loop // 工作线程入口函数
- do_workthread_loop
- while(){kcp_client_.update();} // 工作线程中 kcp 的 tick,kcp update 时间间隔是 KCP_UPDATE_INTERVAL 5ms
c 封装的成员变量有:
kcp_client kcp_client_;
相关状态变量
d kcp client 创建实例:
- asio_kcp::kcp_client_wrap.NET;
- Client client;
- net.set_event_callback(Client::client_event_callback, (void*)(&client));
- int ret = net.connect(0, "127.0.0.1", 32323);
- asio_kcp::millisecond_sleep(10);
- net.send_msg(std::string("1234567890"));
- asio_kcp::millisecond_sleep(510);
(2)kcp_client 类
a 提供方法接口如下:
- connect_async
- init_udp_connect
- // 设置 udp 连接的状态, in_connect_stage_置为 true, 获得当前时间作为 connect_start_time_
- send_msg // 主线程调用此函数将待发送消息 push 到发送队列中, 供工作线程使用
- send_msg_queue_.push(msg);
- update
- do_asio_kcp_connect // 向 udp server 发送 "标志连接" 的消息, 并请求 udp server 端分配 kcp conv
- // 若 udp 连接成功 (connect_succeed_字段为 true, 当 client 的 kcp 初始化完成)
- do_send_msg_in_queue // 一次全部取出发送队列中的消息, 并调用 ikcp_send, 交给 kcp 模块进行处理
- while(){ikcp_send();}
- do_recv_udp_packet_in_loop
- recv
- handle_udp_packet
- is_disconnect_packet // 是否断连消息
- ikcp_input // 交给 kcp 将收到的 udp 消息由 kcp 消息格式转化为应用层消息格式
- while(1){recv_udp_package_from_kcp();}//
- //recv_udp_package_from_kcp()的内容:
- ikcp_recv // 利用 ikcp_recv 获取经 kcp 解析 (去掉头) 后的应用层消息
- ikcp_update
- // 距上次 ts_flush 超过一定阈值, 则调用 ikcp_flush, 并更新 kcp->ts_flush
- ikcp_flush // 利用 ikcp_output 调用注册的回调函数将各类 kcp 消息 (ack / 数据 / 请求窗口 / 告知窗口) 发送给 udp server
b 包含的私有方法:
- init_udp_connect
- //servaddr_内容填充, udp 服务端 ip, 监听端口号,
- socket //SOCK_DGRAM, 建立 udp socket, 设置为非阻塞模式
- bind // 填充 struct sockaddr_in bind_addr, 利用 bind 绑定本地端口号
- connect(udp_socket_, &servaddr_,...) //
- connect_timeout //kcp 重连时间间隔 500ms
- need_send_connect_packet
- do_asio_kcp_connect
- do_send_connect_packet
- try_recv_connect_back_packet //
- udp_output // 静态方法, 在 kcp 模块中被调用, 下面方法所属的应用层类实例指针为 kcp_client*
- ((kcp_client*)user)->send_udp_package(buf, len); //
- send// 利用应用层创建的 udp 网络连接将 kcp 封装后的 udp 消息发送出去
- send_udp_package
- send// 利用应用层创建的 udp 网络连接将 kcp 封装后的 udp 消息发送出去
- do_send_connect_packet
- making_connect_packet //udp client 向 udp server 发送特定 "标志连接" 的消息, 用于 udp 服务端记录 udp client 信息
- send
- do_recv_udp_packet_in_loop
- do_send_msg_in_queue
- handle_udp_packet
- try_recv_connect_back_packet
- recv // 等待接收 "send_back_conv_packet", 消息体内容:"asio_kcp_connect_back_package get_conv:"
- grab_conv_from_send_back_conv_packet // 从 udp 服务端接收到上面消息后, 解析出消息中包含的 conv 字段值(udp server 分配)
- init_kcp(conv);// 利用服务端发来的 conv 来初始化 client 端的 kcp
- // 状态置位, in_connect_stage_置为 false,connect_succeed_置为 true
- init_kcp
- p_kcp_ = ikcp_create(conv, (void*)this); // 创建 kcp 对象, 并将应用层的上下文信息指针传递给 kcp 模块
- // 注册应用层的 udp 发送消息的回调 kcp_client::udp_output
- ikcp_nodelay(p_kcp_, 1, 2, 1, 1);// 为 kcp 设置特定模式
c 封装的成员变量有:
- in_connect_stage_; //udp 连接状态
- threadsafe_queue_mutex<std::string> send_msg_queue_;// 线程安全的发送队列, 主线程生产, 工作线程消费
- int udp_port_bind_;// 本地 udp 端口号
- std::string server_ip_;//udp 服务器 ip
- int server_port_;//udp 服务器监听端口号
- int udp_socket_;//fd
- char udp_data_[1024 * 4];// 缓存区
- ikcpcb* p_kcp_;// 本 client 对应的 kcp 信息
(3)client_with_asio 类, 继承自: private boost::noncopyable 基类 ========= 使用 asio 库的示例
a 提供方法接口如下:
b 包含的私有方法:
c 封装的成员变量有:
- asio_kcp::kcp_client kcp_client_;
- // 几个定时器
- boost::asio::deadline_timer client_timer_;
- boost::asio::deadline_timer client_timer_send_msg_;
- // 几个整数 vector (包含接收包的间隔的 vector)
总结: udp 客户端的逻辑
整体, udp 连接的建立过程, 和, kcp 的初始化和创建过程:
1 udp client 的主线程
- connect //main 函数中调用 connect 进行 kcp client 的初始化
- kcp_client_.connect_async
- init_udp_connect
- //servaddr_内容填充, udp 服务端 ip, 监听端口号,
- socket //SOCK_DGRAM, 建立 udp socket, 设置为非阻塞模式
- bind // 填充 struct sockaddr_in bind_addr, 利用 bind 绑定本地端口号
- connect(udp_socket_, &servaddr_,...) //
- // 设置 udp 连接的状态, in_connect_stage_置为 true, 获得当前时间作为 connect_start_time_
- do_asio_kcp_connect_loop
- while(){kcp_client_.update();} // 主线程中 kcp 的 tick
- //kcp_client_.update()执行的操作
- do_asio_kcp_connect // 向 udp server 发送 "标志连接" 的消息, 并请求 udp server 端分配 kcp conv
- // 若 udp 连接成功 (connect_succeed_字段为 true, 当 client 的 kcp 初始化完成)
- do_send_msg_in_queue // 一次全部取出发送队列中的消息, 并调用 ikcp_send, 交给 kcp 模块进行处理
- while(){ikcp_send();}
- do_recv_udp_packet_in_loop
- recv
- handle_udp_packet
- is_disconnect_packet // 是否断连消息
- ikcp_input // 交给 kcp 将收到的 udp 消息由 kcp 消息格式转化为应用层消息格式
- while(1){recv_udp_package_from_kcp();}//
- //recv_udp_package_from_kcp()的内容:
- ikcp_recv // 利用 ikcp_recv 获取经 kcp 解析 (去掉头) 后的应用层消息
- //while 中调用 recv_udp_package_from_kcp 后, 又调用下面函数
- (*pevent_func_)(p_kcp_->conv, eRcvMsg, msg, event_callback_var_); //pevent_func_在 set_event_callback()中被注册,
- // 这里的示例是 Client::client_event_callback(上层业务处理函数, 传入的参数列表是:{kcp conv,udp 消息类型 eEventType 类型, 消息内容, event_func_var_(上层注册时传递的指针)})
- //eEventType 在 udp client 定义在 kcp_client.hpp 中
- ikcp_update
- // 距上次 ts_flush 超过一定阈值, 则调用 ikcp_flush, 并更新 kcp->ts_flush
- ikcp_flush // 利用 ikcp_output 调用注册的回调函数将各类 kcp 消息 (ack / 数据 / 请求窗口 / 告知窗口) 发送给 udp server
- start_workthread // 创建工作线程
2 udp client 的主线程
- workthread_loop
- do_workthread_loop
- while(){kcp_client_.update();} // 工作线程中 kcp 的 tick,kcp update 时间间隔是 KCP_UPDATE_INTERVAL 5ms
- 3 udp_output // 静态方法, 在 kcp 模块中被调用, 下面方法所属的应用层类实例指针为 kcp_client
- ((kcp_client)user)->send_udp_package(buf, len); //
- send// 利用应用层创建的 udp 网络连接将 kcp 封装后的 udp 消息发送出去
udp 服务端
(1)connection_manager 类, udp server 管理多个 udp client 的管理类, 继承自 private boost::noncopyable, public std::enable_shared_from_this 这两个基类,
a 提供方法接口如下:
- connection_manager // 构造函数, 在 udp server 的 main 函数中系统初始化时进行调用
- hook_udp_async_receive // 为 udp server 对应的监听 udp socket 创建回调 connection_manager::handle_udp_receive_from(利用 boost::bind 进行绑定), 和 udp 接收缓存区, 以及 udp 网元信息 udp_remote_endpoint_
- //udp_socket_用 boost::asio::io_service io_service, udp::endpoint(boost::asio::ip::address::from_string(address), udp_port)实参进行初始化
- hook_kcp_timer // 创建 kcp 定时器 kcp_timer_
- stop_all // 断开所有 udp client 的连接
- force_disconnect
- call_event_callback_func // 调用该函数, 将特定消息:"server force disconnect" 传递给上层注册的回掉函数 event_callback_
- connections_.remove_connection // 断开
- set_callback // 将来自应用层上层的业务回调函数保存在该类的 event_callback_成员变量中
- send_msg // 从 connections_中根据 kcp conv 找到对应 udp client 的连接指针的智能指针管理类 connection_ptr, 并调用 send_kcp_msg
- connections_.find_by_conv
- connection::send_kcp_msg
- ikcp_send // 调用 kcp 接口将应用层消息传递给 kcp 模块, 交给 kcp 模块进行 kcp 头的封装和其他处理
- call_event_callback_func
- send_udp_packet
- get_cur_clock
b 包含的私有方法:
- handle_udp_receive_from
- is_connect_packet // 调用公共库中函数判断是否连接包, 消息内容是:"asio_kcp_connect_package get_conv"
- handle_connect_packet // 若是连接包, 则调用该函数,
- udp_socket_.send_to // 向 udp client 发送连接包的响应消息:"asio_kcp_connect_back_package get_conv: %kcp conv"
- connections_.add_new_connection // 并在此时, 将 udp client 的网元信息保存在 udp server 中
- handle_kcp_packet // 其他非连接包的 udp client 发来的包的处理
- ikcp_get_conv // 从应用层收到的 udp 消息中解析出 kcp conv
- connections_.find_by_conv // 利用 conv 找到 udp client 的网元连接信息
- connection::input// 获取当前时间戳, 更新 last_packet_recv_time_, 并更新 udp client 的网元信息 udp_remote_endpoint_; 并调用 kcp 接口将应用层接收到的 udp 消息, 交给 kcp 模块处理,
- ikcp_input // 交给 kcp 将收到的 udp 消息由 kcp 消息格式转化为应用层消息格式
- // 调用 ikcp_recv 从 kcp 模块获取解析后的应用层消息, 并进行相关处理
- ikcp_recv
- hook_udp_async_receive
- handle_kcp_time // 该函数是 kcp 定时器 kcp_timer_的超时回调, 每隔 5ms 调用一次
- hook_kcp_timer
- connections_.update_all_kcp(cur_clock_); // 更新所有 udp client 的 kcp tick
- hook_kcp_timer // 设置 kcp 定时器的超时时间 5ms 和异步回调函数 connection_manager::handle_kcp_time
- handle_connect_packet
- handle_kcp_packet
c 封装的成员变量有:
- stopped_ //udp server 正常工作的标志, bool 类型
- std::function<event_callback_t> event_callback_; // 应用层回调
- udp::endpoint udp_remote_endpoint_; //udp server 测的 udp 连接的网元信息
- udp::socket udp_socket_; //udp server 测的 udp socket 信息
- char udp_data_[1024 * 32];//udp server 测的 udp 应用层接收缓存区, udp_packet_max_length = 1080((576-8-20 - 8) * 2)
- connection_container connections_; // 包含了各个 udp client 的 kcp,udp 连接网元等信息
(2)connection_container 类, 继承自 private boost::noncopyable
a 提供方法接口如下:
- get_new_conv //udp server 为多个 udp client 分配全局唯一 kcp conv, 从 1000 递增一个 static 全局变量
- update_all_kcp// 遍历多个 udp client 的 map, 对每个调用下面函数
- connection_manager::update_kcp
- ikcp_update
- // 距上次 ts_flush 超过一定阈值, 则调用 ikcp_flush, 并更新 kcp->ts_flush
- ikcp_flush // 利用 ikcp_output 调用注册的回调函数将各类 kcp 消息 (ack / 数据 / 请求窗口 / 告知窗口) 发送给 udp server
- connection_manager::do_timeout // 超时后将该 udp client 从 map 中删掉
- add_new_connection // 利用传入的 kcp conv 和 udp client 信息 udp::endpoint udp_sender_endpoint 来本地维护多个 udp client 的信息
- connection::create // 传入 connection_manager 指针 manager_ptr,kcp conv,udp_sender_endpoint, 将 manager_ptr 维护在智能指针中
- connection::init_kcp
- connection::set_udp_remote_endpoint
b 包含的私有方法:
c 封装的成员变量有:
std::unordered_map<kcp_conv_t, connection::shared_ptr> connections_; // 每个 kcp 标志 (conv) 和每个 udp client 连接之间的哈希 map
(3)connection 类, udp server 用于管理每一个 udp client 的信息, 继承自 private boost::noncopyable
a 提供方法接口如下:
- is_timeout
- do_timeout
- udp_output //kcp 直接调用的应用层注册的回调
- ((connection*)user)->send_udp_package(buf, len);
- send_kcp_msg
- ikcp_send // 调用 kcp 接口将应用层消息传递给 kcp 模块, 交给 kcp 模块进行 kcp 头的封装和其他处理
- input // 获取当前时间戳, 更新 last_packet_recv_time_, 并更新 udp client 的网元信息 udp_remote_endpoint_; 并调用 kcp 接口将应用层接收到的 udp 消息, 交给 kcp 模块处理,
- ikcp_input
- // 调用 ikcp_recv 从 kcp 模块获取解析后的应用层消息, 并进行相关处理
- ikcp_recv
- update_kcp
- ikcp_update
b 包含的私有方法:
- init_kcp // 同 udp client 的 init_kcp 的实现
- ikcp_create
- // 注册的回调函数是 connection::udp_output
- ikcp_nodelay(p_kcp_, 1, 5, 1, 1);
- udp_output
- send_udp_package
- connection_manager.send_udp_packet
- get_cur_clock
- get_timeout_time
c 封装的成员变量有:
- std::weak_ptr<connection_manager> connection_manager_weak_ptr_;
- kcp_conv_t conv_; // 本 udp 连接的标志: kcp conv
- ikcpcb* p_kcp_;
- udp::endpoint udp_remote_endpoint_; //udp client 的网元信息
- uint32_t last_packet_recv_time_; // 上次从 udp client 收到包的时间戳
(4)server 类
a 提供方法接口如下:
- server // 构造函数,
- // 添加各个信号 SIGINT,SIGTERM,SIGQUIT 到 signals_, 并注册信号处理的回调函数 server::handle_stop
- // 注册应用层的正常事件回调 server::event_callback
- connection_manager::set_callback // 将来自应用层上层的业务回调函数 server::event_callback 保存在该类的 event_callback_成员变量中
- run
- io_service_.run();// 阻塞, 直到所有的异步操作完成,
b 包含的私有方法:
- handle_stop
- event_callback // 被调用的地方: connection_manager::call_event_callback_func
- // 若消息类型是 kcp_svr::eRcvMsg, 则调用下面函数
- kcp_server_.send_msg(conv, msg);
- connection_manager::send_msg // 从 connections_中根据 kcp conv 找到对应 udp client 的连接指针的智能指针管理类 connection_ptr, 并调用 send_kcp_msg
- connections_.find_by_conv
- connection::send_kcp_msg
- ikcp_send // 调用 kcp 接口将应用层消息传递给 kcp 模块, 交给 kcp 模块进行 kcp 头的封装和其他处理
- hook_test_timer
- handle_test_timer
- test_force_disconnect
c 封装的成员变量有:
- boost::asio::io_service io_service_; // 用作执行异步操作
- boost::asio::signal_set signals_;// 用于注册各种进程终止通知函数
- bool stopped_;
- kcp_svr::server kcp_server_; // 管理了各个 udp client 连接信息的 udp+kcp 管理类
- boost::asio::deadline_timer test_timer_;
udp server 端的示例 main 函数
- main
- server s(argv[1], argv[2]); // 初始化 udp server, 构造函数,
- // 添加各个信号 SIGINT,SIGTERM,SIGQUIT 到 signals_, 并注册信号处理的回调函数 server::handle_stop
- // 注册应用层的正常事件回调 server::event_callback
- new connection_manager // 调用构造函数 connection_manager, 在 udp server 的 main 函数中系统初始化时进行调用
- hook_udp_async_receive // 为 udp server 对应的监听 udp socket 创建回调 connection_manager::handle_udp_receive_from(利用 boost::bind 进行绑定), 和 udp 接收缓存区, 以及 udp 网元信息 udp_remote_endpoint_
- //udp_socket_用 boost::asio::io_service io_service, udp::endpoint(boost::asio::ip::address::from_string(address), udp_port)实参进行初始化
- hook_kcp_timer // 创建 kcp 定时器 kcp_timer_
- connection_manager::set_callback // 将来自应用层上层的业务回调函数 server::event_callback 保存在该类的 event_callback_成员变量中
- event_callback_=// 保存在本地
- s.run();
- handle_udp_receive_from // 当 udp server socket 收到消息时触发调用, 从接收包中解析出 kcp conv, 进而判断是属于哪个 udp client 的消息
- is_connect_packet // 调用公共库中函数判断是否连接包, 消息内容是:"asio_kcp_connect_package get_conv"
- handle_connect_packet // 若是连接包, 则调用该函数,
- udp_socket_.send_to // 向 udp client 发送连接包的响应消息:"asio_kcp_connect_back_package get_conv: %kcp conv"
- connections_.add_new_connection // 并在此时, 将 udp client 的网元信息保存在 udp server 中
- handle_kcp_packet // 其他非连接包的 udp client 发来的包的处理
- ikcp_get_conv // 从应用层收到的 udp 消息中解析出 kcp conv
- connections_.find_by_conv // 利用 conv 找到 udp client 的网元连接信息
- connection::input// 获取当前时间戳, 更新 last_packet_recv_time_, 并更新 udp client 的网元信息 udp_remote_endpoint_; 并调用 kcp 接口将应用层接收到的 udp 消息, 交给 kcp 模块处理,
- ikcp_input // 交给 kcp 将收到的 udp 消息由 kcp 消息格式转化为应用层消息格式
- // 调用 ikcp_recv 从 kcp 模块获取解析后的应用层消息, 并进行相关处理
- ikcp_recv
- connection_manager::call_event_callback_func // 调用上层业务注册的回调, 这里的示例是,
- event_callback_ // 被调用的地方: connection_manager::call_event_callback_func
- // 若消息类型是 kcp_svr::eRcvMsg, 则调用下面函数
- kcp_server_.send_msg(conv, msg);
- connection_manager::send_msg // 从 connections_中根据 kcp conv 找到对应 udp client 的连接指针的智能指针管理类 connection_ptr, 并调用 send_kcp_msg
- connections_.find_by_conv
- connection::send_kcp_msg
- ikcp_send // 调用 kcp 接口将应用层消息传递给 kcp 模块, 交给 kcp 模块进行 kcp 头的封装和其他处理
在 udp client 和 udp server 之间的几种不同 udp 消息类型:
服务端定义在 kcp_typedef.hpp 中 /server_lib/
- enum eEventType
- {
- eConnect,
- eDisconnect,
- eRcvMsg,
- eLagNotify,
- eCountOfEventType
- };
来源: https://www.cnblogs.com/studyofadeerlet/p/11469551.html