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

字號(hào):


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