不吐不快
當(dāng)你習(xí)慣了現(xiàn)有WEB服務(wù)器,諸如nginx、apache,JAVA應(yīng)用服務(wù)器Tomcat等,你就不能不注意HTTP請(qǐng)求的響應(yīng)超時(shí)時(shí)間,需要小心,尤其是反向代理時(shí)。當(dāng)你可以自由控制請(qǐng)求timeout超時(shí)時(shí),那是怎樣一個(gè)快意。
在libev中使用timeout,沒有像java那樣封裝的完善,一切都很原始,但確實(shí)鋒利多了。
長(zhǎng)輪詢
一般長(zhǎng)輪詢需要定義超時(shí)時(shí)間,一旦超時(shí),服務(wù)器端會(huì)主動(dòng)斷開連接。無(wú)論是xhr形式的長(zhǎng)輪詢,還是jsonp長(zhǎng)輪詢,在服務(wù)器端處理沒有多大差別,輸出數(shù)據(jù)有異。
輸出頭部
一般優(yōu)先輸出頭部,告訴瀏覽器,需要保持長(zhǎng)連接,當(dāng)然,這需要瀏覽器支持http 1.1協(xié)議,并且明確的注明當(dāng)前連接為一直保持著:keep-alive:
char heaer_str[200] = "";
strcat(heaer_str, "HTTP/1.1 200 OK\r\n");
strcat(heaer_str, "Content-Type: text/plain; charset=UTF-8\r\n");
strcat(heaer_str, "Connection: keep-alive\r\n");
strcat(heaer_str, "\r\n");
write_msg(client, heaer_str);
定時(shí)器啟動(dòng),等待
連接什么時(shí)候關(guān)閉,需要在代碼中手動(dòng)控制,除非瀏覽器端在發(fā)出請(qǐng)求等待響應(yīng)期間出現(xiàn)異常,無(wú)故斷開了連接。設(shè)服務(wù)器端設(shè)定好連接持續(xù)時(shí)間為30秒,那么就應(yīng)該啟動(dòng)一個(gè)定時(shí)器,除非所使用的語(yǔ)言層面提供了內(nèi)置支持。
client->timeout.data = client;
ev_timer_init(&client->timeout, timeout_cb, 30.0, 0); //30s
ev_timer_start(loop, &client->timeout);
定時(shí)器start之后,觸發(fā)的函數(shù)timeout_cb:
1 static void timeout_cb(EV_P_ struct ev_timer *timer, int revents) {
2 if (EV_ERROR & revents) {
3 fprintf(stderr, "error event in timer_beat\n");
4 return ;
5 }
6
7 if (timer == NULL) {
8 fprintf(stderr, "the timer is NULL now !\n");
9 return;
10 }
11
12 client_t *client = timer->data;
13
14 if (client == NULL) {
15 fprintf(stderr, "Timeout the client is NULL !\n");
16 return;
17 }
18
19 write_msg(client, HTML_RESPONSE_ECHO);
20 free_res(loop, client);
21 }
可以看到,定時(shí)器觸發(fā)之后,本例中將輸出一串預(yù)先定義好的文字,然后關(guān)閉連接。
如何關(guān)閉觸發(fā)器,則很簡(jiǎn)單:
ev_timer *timer = &client->timeout;
if (timer != NULL && (timer->data != NULL)) {
ev_timer_stop(loop, timer);
}
編譯運(yùn)行
編譯一下:
gcc longpolling.c -o longpolling ../include/libev.a ../include/http-parser/http_parser.o -lm
運(yùn)行它:
./long_polling
然后測(cè)試:
curl -i http://192.168.190.150:9000/long_polling
可以先看到頭部:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Connection: keep-alive
等到30秒后輸出具體的文字內(nèi)容:
The timeout(30s) had passed, you are welcome ~!
小結(jié)
所演示的長(zhǎng)輪詢,沒有什么難度,HTTP 1.1頭部輸出,定時(shí)器啟動(dòng),然后等待輸出。
libev內(nèi)含的timer組件簡(jiǎn)單易用,控制方便,但不算是最佳實(shí)踐,官方文檔給出了若干種最佳實(shí)踐方式。具體可參閱:
http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#codeevtimercoderelativeandopti
完整代碼