新聞中心
在網(wǎng)絡(luò)編程中,我們經(jīng)常需要同時(shí)監(jiān)視多個(gè)文件描述符,例如需要監(jiān)聽多個(gè)客戶端連接請(qǐng)求,或者同時(shí)處理多個(gè)文件IO操作等等。這時(shí)候,就需要用到select函數(shù)。

成都創(chuàng)新互聯(lián)公司主要從事網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)舟曲,十多年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來(lái)電咨詢建站服務(wù):18980820575
select函數(shù)可以同時(shí)監(jiān)視多個(gè)文件描述符的狀態(tài),包括可讀、可寫和異常等狀態(tài)。當(dāng)某個(gè)文件描述符的狀態(tài)發(fā)生變化時(shí),select函數(shù)會(huì)返回這個(gè)文件描述符。使用select函數(shù)可以實(shí)現(xiàn)高效的事件驅(qū)動(dòng)編程。
本文將深入講解select函數(shù)的原理和使用方法。
一、select函數(shù)原理
select函數(shù)的原理是通過(guò)輪詢的方式來(lái)查詢所有需要監(jiān)視的文件描述符的狀態(tài)是否發(fā)生變化,一旦有文件描述符的狀態(tài)發(fā)生變化,select函數(shù)就會(huì)返回這個(gè)文件描述符。
select函數(shù)有三個(gè)參數(shù),分別是:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
其中,nfds是需要監(jiān)視的更大文件描述符數(shù)加1,readfds、writefds、exceptfds分別是文件描述符,表示需要監(jiān)視可讀、可寫和異常狀態(tài)的文件描述符,如果不需要監(jiān)視某種狀態(tài),則為NULL。timeout表示select函數(shù)的超時(shí)時(shí)間。
select函數(shù)返回值是發(fā)生變化的文件描述符的個(gè)數(shù),如果超時(shí)則返回0,如果返回-1則表示出錯(cuò)。
可以通過(guò)以下代碼來(lái)進(jìn)行select函數(shù)操作的流程演示:
#include
#include
int mn()
{
fd_set rfds;
struct timeval tv;
int retval;
/* 每次運(yùn)行前清空 */
FD_ZERO(&rfds);
/* 將需要監(jiān)視的文件描述符加入中 */
FD_SET(STDIN_FILENO, &rfds);
/* 超時(shí)時(shí)間為10秒 */
tv.tv_sec = 10;
tv.tv_usec = 0;
/* 監(jiān)視文件描述符狀態(tài) */
retval = select(STDIN_FILENO + 1, &rfds, NULL, NULL, &tv);
if (retval == -1)
{
perror(“select”);
}
else if (retval)
{
/* 文件描述符狀態(tài)發(fā)生變化 */
if (FD_ISSET(STDIN_FILENO, &rfds))
{
printf(“Data is avlable now.\n”);
}
}
else
{
printf(“No data within ten seconds.\n”);
}
return 0;
}
以上代碼將監(jiān)視標(biāo)準(zhǔn)輸入文件描述符的可讀狀態(tài),如果在超時(shí)范圍內(nèi)有數(shù)據(jù)可讀,則輸出“Data is avlable now.”,如果超時(shí)則輸出“No data within ten seconds.”。
二、select函數(shù)使用注意事項(xiàng)
使用select函數(shù)需要注意以下幾點(diǎn):
1. nfds參數(shù)的值應(yīng)該是需要監(jiān)視的更大文件描述符數(shù)加1,避免遺漏未監(jiān)視的文件描述符。
2. 如果不需要監(jiān)視某種狀態(tài),則對(duì)應(yīng)的fd_set參數(shù)應(yīng)該為NULL,否則可能會(huì)導(dǎo)致程序阻塞。
3. select函數(shù)的timeout參數(shù)可能會(huì)受到系統(tǒng)調(diào)度的影響而不準(zhǔn)確,因此建議在程序中設(shè)置超時(shí)時(shí)間,并進(jìn)行合理處理。
4. 對(duì)于返回值為-1的情況,錯(cuò)誤原因可以通過(guò)perror函數(shù)來(lái)輸出,方便調(diào)試程序。
5. 在多進(jìn)程、多線程程序中使用select函數(shù)需要進(jìn)行同步,避免出現(xiàn)競(jìng)爭(zhēng)條件。
三、select函數(shù)實(shí)現(xiàn)模型推薦
在實(shí)際使用中,建議使用事件驅(qū)動(dòng)編程模型,即使用select函數(shù)來(lái)實(shí)現(xiàn)事件循環(huán),而不是使用fork或者線程等并發(fā)模型。
事件驅(qū)動(dòng)編程模型的主要優(yōu)點(diǎn)是可以減少系統(tǒng)資源消耗和排除競(jìng)爭(zhēng)條件等問(wèn)題,保證程序安全和穩(wěn)定性。
下面是事件驅(qū)動(dòng)編程模型的示例代碼:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define SERVER_PORT 12345
int mn()
{
int sockfd, client_sockfd;
socklen_t clilen;
struct sockaddr_in servaddr;
struct sockaddr_in cliaddr;
fd_set rfds, allfs;
int maxfd;
int retval;
/* 創(chuàng)建監(jiān)聽套接字 */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd
{
perror(“socket”);
exit(1);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERVER_PORT);
if (bind(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr))
{
perror(“bind”);
exit(1);
}
if (listen(sockfd, 5)
{
perror(“l(fā)isten”);
exit(1);
}
FD_ZERO(&allfs);
FD_SET(sockfd, &allfs);
maxfd = sockfd;
printf(“Select server start.\n”);
while (1)
{
rfds = allfs;
retval = select(maxfd + 1, &rfds, NULL, NULL, NULL);
if (retval == -1)
{
perror(“select”);
}
else if (retval)
{
/* 處理監(jiān)聽套接字讀事件 */
if (FD_ISSET(sockfd, &rfds))
{
clilen = sizeof(cliaddr);
client_sockfd = accept(sockfd, (struct sockaddr*)&cliaddr, &clilen);
if (client_sockfd
{
perror(“accept”);
continue;
}
printf(“Client connected.\n”);
/* 添加客戶端套接字描述符 */
FD_SET(client_sockfd, &allfs);
if (client_sockfd > maxfd)
{
maxfd = client_sockfd;
}
}
else
{
/* 處理客戶端套接字讀事件 */
for (int i=sockfd+1; i
{
if (FD_ISSET(i, &rfds))
{
char buf[1024];
memset(buf, 0, sizeof(buf));
ssize_t n = read(i, buf, sizeof(buf)-1);
if (n
{
perror(“read”);
continue;
}
else if (n == 0)
{
printf(“Client disconnected.\n”);
/* 刪除客戶端套接字描述符 */
FD_CLR(i, &allfs);
close(i);
}
else
{
buf[n] = ‘\0’;
printf(“Recv: %s\n”, buf);
/* 回復(fù)客戶端套接字 */
ssize_t nwrite = write(i, buf, strlen(buf));
if (nwrite
{
perror(“write”);
}
}
}
}
}
}
}
close(sockfd);
return 0;
}
以上代碼是一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)回顯服務(wù)端程序,它使用事件驅(qū)動(dòng)編程模型來(lái)實(shí)現(xiàn)高效的網(wǎng)絡(luò)編程。程序使用select函數(shù)來(lái)監(jiān)視所有連接的客戶端套接字描述符和監(jiān)聽套接字描述符的讀事件。
相關(guān)問(wèn)題拓展閱讀:
- linux 下 select函數(shù) 之一個(gè)參數(shù) 更大文件句柄 為什么要+1
linux 下 select函數(shù) 之一個(gè)參數(shù) 更大文件句柄 為什么要+1
因?yàn)槲募枋龇菑?開始的
可以將之一個(gè)參御鏈數(shù)設(shè)置為FD_SETSIZE,值枝拍較大
不過(guò)通常應(yīng)用程序也就4、5個(gè)描述符,用不了那么大鎮(zhèn)搭孫
linux c select函數(shù)的介紹就聊到這里吧,感謝你花時(shí)間閱讀本站內(nèi)容,更多關(guān)于linux c select函數(shù),Linux C編程:深入理解select函數(shù),linux 下 select函數(shù) 之一個(gè)參數(shù) 更大文件句柄 為什么要+1的信息別忘了在本站進(jìn)行查找喔。
創(chuàng)新互聯(lián)成都網(wǎng)站建設(shè)公司提供專業(yè)的建站服務(wù),為您量身定制,歡迎來(lái)電(028-86922220)為您打造專屬于企業(yè)本身的網(wǎng)絡(luò)品牌形象。
成都創(chuàng)新互聯(lián)品牌官網(wǎng)提供專業(yè)的網(wǎng)站建設(shè)、設(shè)計(jì)、制作等服務(wù),是一家以網(wǎng)站建設(shè)為主要業(yè)務(wù)的公司,在網(wǎng)站建設(shè)、設(shè)計(jì)和制作領(lǐng)域具有豐富的經(jīng)驗(yàn)。
當(dāng)前標(biāo)題:LinuxC編程:深入理解select函數(shù)(linuxcselect函數(shù))
URL地址:http://www.dlmjj.cn/article/dhdghce.html


咨詢
建站咨詢
