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í)例。