libevent(3):event_loop是如何处理网络I/O的?

RT

参考libevent自带的例子client_test来分析。

#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <event.h>

void on_event( int s, short ev, void *arg )
{
    static int count = 0;
    count ++;
    if( count < 10 )
    {
        //event_add( (event*)arg, 0 );
    }

    if( ev & EV_READ )
    {
        printf( "read event\n" );
        char buf[256] = {0};
        int ret = recv( (SOCKET)s, buf, sizeof( buf ), 0 );
        if( ret > 0 )
        {
            printf( "read data : %s[%d bytes]\n", buf, ret );
            send( (SOCKET)s, buf, ret, 0 );
        }
        else
        {
            printf( "read failed : %d\n", WSAGetLastError() );
        }
    }

    if( ev & EV_WRITE )
    {
        printf( "write event\n" );
    }

    Sleep( 10 );
}

int main()
{
    int ret = 0;
    sockaddr_in addr;

    event_base *base = event_init();
    printf( "%s\n", event_base_get_method( base ) );

    SOCKET s = socket( AF_INET, SOCK_STREAM, 0 );
    memset( &addr, 0, sizeof( addr ) );
    addr.sin_family = AF_INET;
    addr.sin_port = htons( 8001 );
    addr.sin_addr.s_addr = inet_addr( "127.0.0.1" );

    ret = connect( s, (sockaddr*)&addr, sizeof( addr ) );
    if( ret >= 0 ) {
        printf( "connect ok\n" );
    } else {
        printf( "connect failed : %d\n", WSAGetLastError() );
    }

    event ev;
    event_set( &ev, (int)s, EV_READ | EV_WRITE, on_event, &ev );
    event_add( &ev, 0 );
    
    event_dispatch();
    
    closesocket( s );
    event_base_free( base );
    return 0;
}

其具体执行流程为:

event_set --> event_add --> evsel->dispatch --> win32_dispatch --> select --> event_process_active --> (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);

event_set:用户将指定在该套接字上面进行READ和WRITE监听事件。

event_add:加到主事件循环中

evsel->dispatch:多路复用器使用不同的组件分发事件(例如:在windows上面就是用win32_dispatch来分发事件)

select:标准的select监听套接字是否可用

event_process_active:若套接字还活着,就执行其预先设定的回调函数


问:我如何不断的发送/接收数据?

答:都在on_event里面处理。








请解释下这个代码:int main(int argc, char *argv[]) { std::cout << "Beerocks Controller Process Start" << std::endl; #ifdef INCLUDE_BREAKPAD breakpad_ExceptionHandler(); #endif init_signals(); // Check for version query first, handle and exit if requested. std::string module_description; std::ofstream versionfile; if (beerocks::version::handle_version_query(argc, argv, module_description)) { return 0; } #ifdef ENABLE_NBAPI auto amxrt = std::make_shared<beerocks::nbapi::Amxrt>(); //init amxrt and parse command line options amxrt_cmd_line_add_option(0, &#39;k&#39;, "kill", no_argument, "kill the process", nullptr); if (auto init = (amxrt->Initialize(argc, argv, handle_cmd_line_arg) != 0)) { std::cout << "Beerocks Agent Process Failed to initalize the amxrt lib." << "amxrt_config_init returned : " << init << " shutting down!" << std::endl; return init; } guarantee = amxrt; (void)guarantee.use_count(); #else int opt; while ((opt = getopt(argc, argv, "kh")) != -1) { switch (opt) { case &#39;k&#39;: s_kill_master = true; break; case &#39;h&#39;: std::cout << "Usage: " << argv[0] << " -k {kill master}" << std::endl; return 1; default: std::cerr << "Unknown option: " << static_cast<char>(optopt) << std::endl; return 1; } } #endif // only kill and exit if (s_kill_master) { return 0; } // Initialize the BPL (Beerocks Platform Library) if (beerocks::bpl::bpl_init() < 0) { LOG(ERROR) << "Failed to initialize BPL!"; return false; } // read master config file std::string master_config_file_path = CONF_FILES_WRITABLE_PATH + std::string(BEEROCKS_CONTROLLER) + ".conf"; //search first in platform-specific default directory beerocks::config_file::sConfigMaster beerocks_master_conf; if (!beerocks::config_file::read_master_config_file(master_config_file_path, beerocks_master_conf)) { master_config_file_path = mapf::utils::get_install_path() + "config/" + std::string(BEEROCKS_CONTROLLER) + ".conf"; // if not found, search in beerocks path if (!beerocks::config_file::read_master_config_file(master_config_file_path, beerocks_master_conf)) { std::cout << "config file &#39;" << master_config_file_path << "&#39; args error." << std::endl; return 1; } } // read slave config file std::string slave_config_file_path = CONF_FILES_WRITABLE_PATH + std::string(BEEROCKS_AGENT) + ".conf"; //search first in platform-specific default directory beerocks::config_file::sConfigSlave beerocks_slave_conf; if (!beerocks::config_file::read_slave_config_file(slave_config_file_path, beerocks_slave_conf)) { slave_config_file_path = mapf::utils::get_install_path() + "config/" + std::string(BEEROCKS_AGENT) + ".conf"; // if not found, search in beerocks path if (!beerocks::config_file::read_slave_config_file(slave_config_file_path, beerocks_slave_conf)) { std::cout << "config file &#39;" << slave_config_file_path << "&#39; args error." << std::endl; return 1; } } std::string base_master_name = std::string(BEEROCKS_CONTROLLER); //kill running master beerocks::os_utils::kill_pid(beerocks_master_conf.temp_path + "pid/", base_master_name); //init logger beerocks::logging logger(base_master_name, beerocks_master_conf.sLog); s_pLogger = &logger; logger.apply_settings(); LOG(INFO) << std::endl << "Running " << base_master_name << " Version " << BEEROCKS_VERSION << " Build date " << BEEROCKS_BUILD_DATE << std::endl << std::endl; beerocks::version::log_version(argc, argv); versionfile.open(beerocks_master_conf.temp_path + "beerocks_master_version"); versionfile << BEEROCKS_VERSION << std::endl << BEEROCKS_REVISION; versionfile.close(); // Redirect stdout / stderr if (logger.get_log_files_enabled()) { beerocks::os_utils::redirect_console_std(beerocks_master_conf.sLog.files_path + base_master_name + "_std.log"); } //write pid file beerocks::os_utils::write_pid_file(beerocks_master_conf.temp_path, base_master_name); std::string pid_file_path = beerocks_master_conf.temp_path + "pid/" + base_master_name; // for file touching // Create application event loop to wait for blocking I/O operations. auto event_loop = std::make_shared<beerocks::EventLoopImpl>(); LOG_IF(!event_loop, FATAL) << "Unable to create event loop!"; // Create timer factory to create instances of timers. auto timer_factory = std::make_shared<beerocks::TimerFactoryImpl>(); LOG_IF(!timer_factory, FATAL) << "Unable to create timer factory!"; // Create timer manager to help using application timers. auto timer_manager = std::make_shared<beerocks::TimerManagerImpl>(timer_factory, event_loop); LOG_IF(!timer_manager, FATAL) << "Unable to create timer manager!"; // Create UDS address where the server socket will listen for incoming connection requests. std::string uds_path = beerocks_slave_conf.temp_path + "/" + std::string(BEEROCKS_CONTROLLER_UDS); auto uds_address = beerocks::net::UdsAddress::create_instance(uds_path); LOG_IF(!uds_address, FATAL) << "Unable to create UDS server address!"; // Create server to exchange CMDU messages with clients connected through a UDS socket auto cmdu_server = beerocks::CmduServerFactory::create_instance(uds_address, event_loop); LOG_IF(!cmdu_server, FATAL) << "Unable to create CMDU server!"; beerocks::net::network_utils::iface_info bridge_info; const auto &bridge_iface = beerocks_slave_conf.bridge_iface; if (beerocks::net::network_utils::get_iface_info(bridge_info, bridge_iface) != 0) { LOG(ERROR) << "Failed reading addresses from the bridge!"; return 0; } #ifdef ENABLE_NBAPI auto on_action_handlers = prplmesh::controller::actions::get_actions_callback_list(); auto events_list = prplmesh::controller::actions::get_events_list(); auto funcs_list = prplmesh::controller::actions::get_func_list(); auto controller_dm_path = mapf::utils::get_install_path() + CONTROLLER_DATAMODEL_PATH; auto amb_dm_obj = std::make_shared<beerocks::nbapi::AmbiorixImpl>( event_loop, on_action_handlers, events_list, funcs_list); LOG_IF(!amb_dm_obj, FATAL) << "Unable to create Ambiorix!"; LOG_IF(!amb_dm_obj->init(controller_dm_path), FATAL) << "Unable to init ambiorix object!"; #else auto amb_dm_obj = std::make_shared<beerocks::nbapi::AmbiorixDummy>(); #endif //ENABLE_NBAPI beerocks::bpl::set_ambiorix_impl_ptr(amb_dm_obj); // fill master configuration son::db::sDbMasterConfig master_conf; fill_master_config(master_conf, beerocks_master_conf); // Set Network.ID to the Data Model if (!amb_dm_obj->set(DATAELEMENTS_ROOT_DM ".Network", "ID", bridge_info.mac)) { LOG(ERROR) << "Failed to add Network.ID, mac: " << bridge_info.mac; return false; } if (!amb_dm_obj->set(DATAELEMENTS_ROOT_DM ".Network", "ControllerID", bridge_info.mac)) { LOG(ERROR) << "Failed to add Network.ControllerID, mac: " << bridge_info.mac; return false; } son::db master_db(master_conf, logger, tlvf::mac_from_string(bridge_info.mac), amb_dm_obj); #ifdef ENABLE_NBAPI prplmesh::controller::actions::g_database = &master_db; #endif // The prplMesh controller needs to be configured with the SSIDs and credentials that have to // be configured on the agents. Even though NBAPI exists to configure this, there is a lot of // existing software out there that doesn&#39;t use it. Therefore, prplMesh should also read the // configuration out of the legacy wireless settings. std::list<son::wireless_utils::sBssInfoConf> wireless_settings; if (beerocks::bpl::bpl_cfg_get_wireless_settings(wireless_settings)) { for (const auto &configuration : wireless_settings) { master_db.add_bss_info_configuration(configuration); } } else { LOG(DEBUG) << "failed to read wireless settings"; } #ifdef USE_PRPLMESH_WHM std::shared_ptr<prplmesh::controller::whm::WifiManager> wifi_manager = nullptr; if (master_conf.use_dataelements_vap_configs) { LOG(INFO) << "use dataelements input as vap config"; } else { LOG(INFO) << "legacy behavior: use Device.Wifi."; wifi_manager = std::make_shared<prplmesh::controller::whm::WifiManager>(event_loop, &master_db); LOG_IF(!wifi_manager, FATAL) << "Unable to create controller WifiManager!"; wifi_manager->subscribe_to_bss_info_config_change(); } #endif // diagnostics_thread diagnostics(master_db); // UCC server must be created in certification mode only and if a valid TCP port has been set uint16_t port = master_db.config.ucc_listener_port; std::unique_ptr<beerocks::UccServer> ucc_server; if (master_db.setting_certification_mode() && (port != 0)) { LOG(INFO) << "Certification mode enabled (listening on port " << port << ")"; // Create server to exchange UCC commands and replies with clients connected through the socket ucc_server = beerocks::UccServerFactory::create_instance(port, event_loop); LOG_IF(!ucc_server, FATAL) << "Unable to create UCC server!"; } // Create broker client factory to create broker clients when requested std::string broker_uds_path = beerocks_slave_conf.temp_path + "/" + std::string(BEEROCKS_BROKER_UDS); auto broker_client_factory = beerocks::btl::create_broker_client_factory(broker_uds_path, event_loop); LOG_IF(!broker_client_factory, FATAL) << "Unable to create broker client factory!"; son::Controller controller(master_db, std::move(broker_client_factory), std::move(ucc_server), std::move(cmdu_server), timer_manager, event_loop); if (!amb_dm_obj->set_current_time(DATAELEMENTS_ROOT_DM ".Network")) { return false; }; LOG_IF(!controller.start(), FATAL) << "Unable to start controller!"; auto touch_time_stamp_timeout = std::chrono::steady_clock::now(); while (g_running) { // Handle signals if (s_signal) { handle_signal(); continue; } if (std::chrono::steady_clock::now() > touch_time_stamp_timeout) { beerocks::os_utils::touch_pid_file(pid_file_path); touch_time_stamp_timeout = std::chrono::steady_clock::now() + std::chrono::seconds(beerocks::TOUCH_PID_TIMEOUT_SECONDS); } // Run application event loop and break on error. if (event_loop->run() < 0) { LOG(ERROR) << "Event loop failure!"; break; } } s_pLogger = nullptr; controller.stop(); beerocks::bpl::bpl_close(); return 0; }
最新发布
08-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值