日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

libcurl实现解析(3) - libcurl对select的使用

發(fā)布時(shí)間:2023/12/4 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 libcurl实现解析(3) - libcurl对select的使用 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.前言

在本系列的前一篇文章中。介紹了libcurl對(duì)poll()的使用。

參考"libcurl原理解析(2) - libcurl對(duì)poll的使用"。

本篇文章主要分析curl_poll()中對(duì)select()的封裝使用。與前一篇類似,我們僅僅分離出與select相關(guān)的代碼。

2.curl_poll函數(shù)分析

這個(gè)函數(shù)中使用到的一些其他的數(shù)據(jù)結(jié)構(gòu),能夠參考前一篇文章中的介紹。本篇不再介紹。

/* 這個(gè)函數(shù)是對(duì)poll()的封裝。假設(shè)poll()不存在,則使用select()替代。 假設(shè)使用的是select(),而且文件描寫敘述符fd太大,超過了FD_SETSIZE,則返回error。 假設(shè)傳入的timeout值是一個(gè)負(fù)數(shù)。則會(huì)無限的等待。直到?jīng)]有有效的fd被提供。

當(dāng)發(fā)生 這樣的情況(沒有有效的fd)時(shí)。則負(fù)數(shù)timeout值會(huì)被忽略,且函數(shù)會(huì)馬上超時(shí)。 返回值: -1 = 系統(tǒng)調(diào)用錯(cuò)誤或fd>=FD_SETSIZE. 0 = timeout. N = 返回的pollfd結(jié)構(gòu)體的個(gè)數(shù),且當(dāng)中的revents成員不為0. */ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) { struct timeval pending_tv; struct timeval *ptimeout; fd_set fds_read; fd_set fds_write; fd_set fds_err; curl_socket_t maxfd; struct timeval initial_tv = { 0, 0 }; bool fds_none = TRUE; //用于驗(yàn)證傳入的ufds數(shù)組是否有效 unsigned int i; int pending_ms = 0; int error; //保存錯(cuò)誤碼 int r; //檢測(cè)全部fd中是否存在有效的fd。 //假設(shè)至少存在一個(gè)有效的fd,則fds_none置為false。停止檢測(cè) if (ufds) { for (i = 0; i < nfds; i++) { if (ufds[i].fd != CURL_SOCKET_BAD) { fds_none = FALSE; break; } } } //假設(shè)全部的fd都是無效的(即bad socket, -1)。則等待一段時(shí)間后。直接返回。 if (fds_none) { r = Curl_wait_ms(timeout_ms); //此函數(shù)會(huì)隨后進(jìn)行分析 return r; } //當(dāng)傳入的timeout值是一個(gè)負(fù)數(shù)(堵塞情形)或者0時(shí)。則無需衡量elapsed time. //否則,獲取當(dāng)前時(shí)間。

if (timeout_ms > 0) { pending_ms = timeout_ms; initial_tv = curlx_tvnow();//調(diào)用gettimeofday()或time()獲取當(dāng)前時(shí)間 } //每次調(diào)用select()前都須要又一次初始化fdset,由于它們既是輸入?yún)?shù)又是輸出參數(shù)。 FD_ZERO(&fds_read); FD_ZERO(&fds_write); FD_ZERO(&fds_err); maxfd = (curl_socket_t)-1; for (i = 0; i < nfds; i++) { ufds[i].revents = 0; if (ufds[i].fd == CURL_SOCKET_BAD) //跳過無效的fd continue; VERIFY_SOCK(ufds[i].fd); //檢測(cè)是否0<=fd<FD_SETSIZE.超出這個(gè)范圍。則返回-1. if (ufds[i].events & (POLLIN | POLLOUT | POLLPRI | POLLRDNORM | POLLWRNORM | POLLRDBAND)) { if (ufds[i].fd > maxfd) //獲取到最大的fd,做為select()的第一個(gè)參數(shù)。 maxfd = ufds[i].fd; if (ufds[i].events & (POLLRDNORM | POLLIN)) FD_SET(ufds[i].fd, &fds_read); if (ufds[i].events & (POLLWRNORM | POLLOUT)) FD_SET(ufds[i].fd, &fds_write); if (ufds[i].events & (POLLRDBAND | POLLPRI)) FD_SET(ufds[i].fd, &fds_err); } } //做為select()的timeout參數(shù) ptimeout = (timeout_ms < 0) ? NULL : &pending_tv; do { if (timeout_ms > 0) { pending_tv.tv_sec = pending_ms / 1000; pending_tv.tv_usec = (pending_ms % 1000) * 1000; } else if (!timeout_ms) { pending_tv.tv_sec = 0; pending_tv.tv_usec = 0; } //真正調(diào)用select(). 第2。3,4參數(shù)已經(jīng)在前面初始化(清空)過了。 r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout); if (r != -1) //select調(diào)用成功,結(jié)束循環(huán) break; //select調(diào)用失敗。返回-1。通過errno能夠獲取到錯(cuò)誤碼。

error = SOCKERRNO; //宏定義。

#define SOCKERRNO (errno) //以下的error_not_EINTR 是宏定義. //#define error_not_EINTR (0 || error != EINTR) if (error && error_not_EINTR) //檢測(cè)是否存在error,且不是EINTR錯(cuò)誤 break; //沒有出錯(cuò)或者存在EINTR錯(cuò)誤。則推斷是否繼續(xù)運(yùn)行select() if (timeout_ms > 0) { //elapsed_ms是宏定義。 //#define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) pending_ms = timeout_ms - elapsed_ms; if (pending_ms <= 0) { r = 0; //模擬select超時(shí)的情形 break; } } } while (r == -1); /*如今能夠?qū)ι厦娴倪@個(gè)while循環(huán)總結(jié)一下: 1.假設(shè)select調(diào)用成功(即返回值>=0),則結(jié)束循環(huán) 2.假設(shè)select調(diào)用失敗(即返回值==-1),則檢測(cè)errno是否為EINTR錯(cuò)誤。 假設(shè)不是EINTR,則結(jié)束循環(huán)。 假設(shè)是EINTR,則檢測(cè)是否已經(jīng)超時(shí)。超時(shí)則結(jié)束循環(huán),沒有超時(shí)則繼續(xù)select()。 */ if (r < 0) //select()調(diào)用失敗 return -1; if (r == 0) //select()超時(shí) return 0; //select()調(diào)用成功, 統(tǒng)計(jì)當(dāng)中狀態(tài)發(fā)生改變的fd的個(gè)數(shù),保存至r. r = 0; for (i = 0; i < nfds; i++) { ufds[i].revents = 0; if (ufds[i].fd == CURL_SOCKET_BAD) continue; if (FD_ISSET(ufds[i].fd, &fds_read)) //fd可讀 ufds[i].revents |= POLLIN; if (FD_ISSET(ufds[i].fd, &fds_write)) //fd可寫 ufds[i].revents |= POLLOUT; if (FD_ISSET(ufds[i].fd, &fds_err)) //fd出錯(cuò) ufds[i].revents |= POLLPRI; if (ufds[i].revents != 0) r++; } return r; }

這個(gè)函數(shù)運(yùn)行完畢后。第一個(gè)輸入?yún)?shù)ufds中的成員revents可能會(huì)被改動(dòng)。最后。函數(shù)返回select()的實(shí)際返回值。

3.curl_wait_ms函數(shù)分析

以下是curl_wait_ms()函數(shù)的詳細(xì)實(shí)現(xiàn)。

也是基于poll或者select來實(shí)現(xiàn)的。這里也僅僅討論它的select()實(shí)現(xiàn)版本號(hào)。


/* 這個(gè)函數(shù)用于等待特定的時(shí)間值。在函數(shù)Curl_socket_ready()以及Curl_poll()中被調(diào)用。 當(dāng)沒有提供不論什么fd來檢測(cè)時(shí)。則僅僅是等待特定的一段時(shí)間。

假設(shè)是在windows平臺(tái)下,則winsock中的poll()以及select()超時(shí)機(jī)制,須要一個(gè)有效的socket fd. 這個(gè)函數(shù)不同意無限等待,假設(shè)傳入的值是0或者負(fù)數(shù)。則馬上返回。 超時(shí)時(shí)間的精度以及最大值。取決于系統(tǒng)。

返回值: -1 = 系統(tǒng)調(diào)用錯(cuò)誤,或無效的輸入值(timeout),或被中斷。 0 = 指定的時(shí)間已經(jīng)超時(shí) */ int Curl_wait_ms(int timeout_ms) { struct timeval pending_tv; struct timeval initial_tv; int pending_ms; int error; int r = 0; if (!timeout_ms) //超時(shí)值為0,馬上返回 return 0; if (timeout_ms < 0) //不能為負(fù)數(shù) { SET_SOCKERRNO(EINVAL); return -1; } pending_ms = timeout_ms; initial_tv = curlx_tvnow(); do { pending_tv.tv_sec = pending_ms / 1000; pending_tv.tv_usec = (pending_ms % 1000) * 1000; r = select(0, NULL, NULL, NULL, &pending_tv); if (r != -1) //select()調(diào)用成功,則跳出循環(huán) break; //select調(diào)用失敗。返回-1。通過errno能夠獲取到錯(cuò)誤碼。 error = SOCKERRNO; //宏定義。

#define SOCKERRNO (errno) //以下的error_not_EINTR 是宏定義. #define error_not_EINTR (0 || error != EINTR) if (error && error_not_EINTR) 檢測(cè)是否存在error,且不是EINTR錯(cuò)誤 break; //elapsed_ms是宏定義: //#define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) pending_ms = timeout_ms - elapsed_ms; if (pending_ms <= 0) { r = 0; //模擬select超時(shí)的情形 break; } } while (r == -1); //確保返回值r僅僅能為-1(超時(shí)失敗)或者0(超時(shí)成功)。

//r不可能大于0,由于傳入到select()函數(shù)的3個(gè)fdset數(shù)組所有都是NULL。假設(shè)select的返回值>0,則說明調(diào)用出問題了。 //故這里會(huì)將r置為-1,即調(diào)用超時(shí)失敗。 if (r) r = -1; return r; }


總結(jié)

以上是生活随笔為你收集整理的libcurl实现解析(3) - libcurl对select的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。