2017年計算機(jī)等級考試二級C++輔導(dǎo):利用ACL開發(fā)并發(fā)網(wǎng)絡(luò)服務(wù)器

字號:


    1、概述
    本節(jié)結(jié)合 "利用ACL庫開發(fā)高并發(fā)半駐留式線程池程序" 和 "利用ACL庫快速創(chuàng)建你的網(wǎng)絡(luò)程序" 兩篇文章的內(nèi)容,創(chuàng)建一個簡單的線程池網(wǎng)絡(luò)服務(wù)器程序。
    2、并發(fā)式網(wǎng)絡(luò)通信實(shí)例
    C代碼
    #include "lib_acl.h" /* 先包含ACL庫頭文件 */
    #include 
    #include 
    /**
    * 單獨(dú)的線程處理來自于客戶端的連接
    * @param arg {void*} 添加任務(wù)時的對象
    */
    static void echo_client_thread(void *arg)
    {
    ACL_VSTREAM *client = (ACL_VSTREAM*) arg;
    char buf[1024];
    int  n;
    /* 設(shè)置客戶端流的讀超時時間為30秒 */
    ACL_VSTREAM_SET_RWTIMO(client, 30);
    /* 循環(huán)讀客戶端的數(shù)據(jù),直到其關(guān)閉或出錯或超時 */
    while (1) {
    /* 等待讀客戶端發(fā)來的數(shù)據(jù) */
    n = acl_vstream_read(client, buf, sizeof(buf));
    if (n == ACL_VSTREAM_EOF)
    break;
    /* 將讀到的數(shù)據(jù)寫回至客戶端流 */
    if (acl_vstream_writen(client, buf, n) == ACL_VSTREAM_EOF)
    break;
    }
    /* 關(guān)閉客戶端流 */
    acl_vstream_close(client);
    }
    /**
    * 創(chuàng)建半駐留線程池的過程
    * @return {acl_pthread_pool_t*} 新創(chuàng)建的線程池句柄
    */
    static acl_pthread_pool_t *create_thread_pool(void)
    {
    acl_pthread_pool_t *thr_pool; /* 線程池句柄 */
    int max_threads = 100; /* 最多并發(fā)100個線程 */
    int idle_timeout = 10; /* 每個工作線程空閑10秒后自動退出 */
    acl_pthread_pool_attr_t attr; /* 線程池初始化時的屬性 */
    /* 初始化線程池對象屬性 */
    acl_pthread_pool_attr_init(&attr);
    acl_pthread_pool_attr_set_threads_limit(&attr, max_threads);
    acl_pthread_pool_attr_set_idle_timeout(&attr, idle_timeout);
    /* 創(chuàng)建半駐留線程句柄 */
    thr_pool = acl_pthread_pool_create(&attr);
    assert(thr_pool);
    return (thr_pool);
    }
    /**
    * 開始運(yùn)行
    * @param addr {const char*} 服務(wù)器監(jiān)聽地址,如:127.0.0.1:8081
    */
    static void run(const char *addr)
    {
    const char *myname = "run";
    acl_pthread_pool_t *thr_pool;
    ACL_VSTREAM *sstream;
    char ebuf[256];
    thr_pool = create_thread_pool();
    /* 監(jiān)聽一個本地地址 */
    sstream = acl_vstream_listen(addr, 128);
    if (sstream == NULL) {
    printf("%s(%d): listen on %s error(%s)\r\n",
    myname, __LINE__, addr,
    acl_last_strerror(ebuf, sizeof(ebuf)));
    return;
    }
    printf("%s: listen %s ok\r\n", myname, addr);
    while (1) {
    /* 等待接受客戶端的連接 */
    client = acl_vstream_accept(sstream, NULL, 0);
    if (client == NULL) {
    printf("%s(%d): accept error(%s)\r\n",
    myname, __LINE__,
    acl_last_strerror(ebuf, sizeof(ebuf)));
    break;
    }
    printf("accept one\r\n");
    /* 獲得一個客戶端連接流 */
    /* 開始處理該客戶端連接流 */
    /**
    * 向線程池中添加一個任務(wù)
    * @param thr_pool 線程池句柄
    * @param echo_client_thread 工作線程的回調(diào)函數(shù)
    * @param client 客戶端數(shù)據(jù)流
    */
    acl_pthread_pool_add(thr_pool, echo_client_thread, client);
    }
    /* 銷毀線程池對象 */
    acl_pthread_pool_destroy(thr_pool);
    }
    /**
    * 初始化過程
    */
    static void init(void)
    {
    /* 初始化ACL庫 */
    acl_init();
    }
    /**
    * 使用提示接口
    * @param procname {cosnt char*} 程序名
    */
    static void usage(const char *procname)
    {
    printf("usage: %s listen_addr\r\n", procname);
    printf("example: %s 127.0.0.1:8081\r\n", procname);
    getchr();  }
    int main(int argc, char *argv[])
    {
    if (argc != 2) {
    usage(argv[0]);
    return (0);
    }
    init();
    run(argv[1]);
    return (0);
    }
    由上可以看出,創(chuàng)建一個并發(fā)式服務(wù)器程序也是如此的簡單。 該例子可以同時運(yùn)行在WIN32平臺及UNIX平臺(Linux, FreeBSD, Solaris-x86).
    3、小結(jié)
    由以上例子可以看出,ACL庫屏蔽底層SOCKET的細(xì)節(jié)操作,使網(wǎng)絡(luò)編程變得簡單,使使用者可以專心于其應(yīng)用,而不是拘泥于SOCKET操作上,另外結(jié)合半駐留線程池的ACL庫就可以開發(fā)高效的并發(fā)網(wǎng)絡(luò)應(yīng)用來。
    當(dāng)然,以上例子也存在一個缺點(diǎn),那就是當(dāng)客戶端并發(fā)連接比較高時,因?yàn)橐粋€連接占用一個線程,所以高并發(fā)時就需要更多的線程(為了啟動更多的線程,可以通過 acl_pthread_pool_set_stacksize 或 acl_pthread_pool_attr_set_stacksize 設(shè)置每個線程的堆棧為較小的值,如 500KB);而采用ACL庫里的另一種編程技術(shù)--非阻塞式IO,可以使一個線程同時處理多個并發(fā)TCP連接,同時可以啟動多個這樣的非阻塞線程,從而可以更好地利用多核(一般是一個核可以啟用一個非阻塞IO線程),將來,我們將會對此類問題進(jìn)行討論,并給出具體實(shí)例。