設定逾時的第二個技術是使用 select 函數。它使用了 select 函數的最後一個逾時參數,對套接字描述符進行了“預讀”。
1. 程式路徑
如果你已經 clone 過這個代碼了,請使用 Git pull 更新一下。本節程式所使用的程式路徑是
unp/program/advcio/read_timeo/read_timeo_select
.
2. 僞代碼
- 用于判斷是否可讀的函數
// 該函數利用 select 函數判斷在 nsec 時間内描述符 fd 是否可讀
int readable_timeo(int fd, int nsec) {
int
fd_set rfds;
struct timeval tv;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = nsec;
tv.tv_usec = 0;
ret = select(fd + 1, &rfds, NULL, NULL, &tv);
- 帶逾時的 recvfrom 函數
int recvfrom_timeo(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen, int nsec) {
int ret;
ret = readable_timeo(sockfd, nsec);
// select 函數傳回 0,表示逾時
if (ret == 0) {
errno = ETIMEDOUT;
ret = -1;
}
else {
ret = recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
}
return
3. 實驗結果
read_timeo_select 是一個 udp 用戶端,實際上就是前面的 udp/basic 程式,隻不過它将 recvfrom 修改成了帶逾時的 recvfrom.
read_timeo_select 向 mars 主機發送了一個封包後,阻塞在 recvfrom_timeo 函數上,因為 mars 主機上的伺服器并未啟動,是以 read_timeo_select 永遠也不可能收到 mars 主機發回的資料。
經曆 5 秒的時候後,recvfrom_timeo 函數逾時傳回。
4. 總結
- 掌握使用 select 函數編寫逾時函數的方法