• asio-kcp源码分析


    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<connection_manager>这两个基类,

    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
        };
    
  • 相关阅读:
    js字符串分割
    Maven打包出错Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test
    Kafka
    linux 切换PHP版本
    linux 查看服务状态及开发端口
    php消息队列
    windows 设置composer 淘宝镜像
    PHP使用CURL详解
    linux php7.0 安装redis扩展
    linux 快速查找安装目录方法
  • 原文地址:https://www.cnblogs.com/studyofadeerlet/p/11469551.html
Copyright © 2020-2023  润新知