我們先來說說最重要的函數(shù)select這個函數(shù),它的原型如下:
創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供合陽網(wǎng)站建設(shè)、合陽做網(wǎng)站、合陽網(wǎng)站設(shè)計、合陽網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、合陽企業(yè)網(wǎng)站模板建站服務(wù),十年合陽做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);
select函數(shù)可以執(zhí)行I/O多路轉(zhuǎn)接。傳給select的參數(shù)告訴內(nèi)核:
1.我們所關(guān)心的描述符
2.對于每個描述符我們所關(guān)心的條件(是否想從一個給定的描述符讀,寫,還是異常條件)
3.愿意等待的時間(永遠(yuǎn)等待,等待一個給定的時間或者根本不等待)
從select返回時,內(nèi)核告訴我們:
1.已準(zhǔn)備好的描述符的總數(shù)量
2.對于讀,寫,異常這3個條件中的每一個,哪些描述符已經(jīng)準(zhǔn)備好
有了上面的返回信息,我們就可以調(diào)用相應(yīng)的I/O函數(shù)(read或者write),并且確知該函數(shù)不會被阻塞。
我們再來說說select這個函數(shù)的返回值和相應(yīng)的參數(shù):
正常返回準(zhǔn)備就緒的描述符數(shù)目,若超時,返回0;出錯時返回-1.
參數(shù):
我們先來說最后一個參數(shù),它是一個指向結(jié)構(gòu)體的指針,這個結(jié)構(gòu)體如下:
struct timeval
{
long tv_sec;
long tv_usec;
}
這個參數(shù)指明了愿意等待的時間長度,單位為秒和微妙。當(dāng)它的值為NULL,說明要永遠(yuǎn)等待。如果捕捉到一個信號則中斷無限等待。當(dāng)所指定的描述符的一個已經(jīng)準(zhǔn)備好或捕捉到一個信號則返回。當(dāng)這個結(jié)構(gòu)體的兩個成員的值均不為0時,則是我們設(shè)定的要指定的秒數(shù)和微秒數(shù)。當(dāng)指定的一個描述符之一已經(jīng)準(zhǔn)備好,或者當(dāng)指定的時間已經(jīng)超過時立即返回。在超時后還沒有一個描述符準(zhǔn)備好,返回0。
中間的 readfds,writefds,exceptfds這三個參數(shù)是指向描述符集的指針。這3個描述符集說明了我們關(guān)心的可讀,可寫或處于異常條件的描述符集合。每個描述符集存儲在一個fd_set數(shù)據(jù)類型中。這個數(shù)據(jù)類型為每一個描述符保持一位。在這里我們簡單的認(rèn)為是一個很大的字節(jié)數(shù)組。
第一個參數(shù) nfds 的意思是“最大文件描述符編號值加1”。因?yàn)槊枋龇麖? 開始,所以要在最大描述符編號上加1.意思是我們我們在所有描述符集當(dāng)中找出最大的一個,然后加1就行了。這里我們也可以將第一個參數(shù)設(shè)置為FD_SETSIZE,它是一個常量值,它指定最大描述符數(shù)(一般是1024),一般而言,此值有點(diǎn)大。通過我們指定最大的描述符數(shù),內(nèi)核就只需在此范圍內(nèi)尋找打開的位,大大節(jié)省了時間。
我們再來說說fd_set這個數(shù)據(jù)類型:
這種數(shù)據(jù)類型的變量經(jīng)常用到以下函數(shù):
int FD_ISSET(int fd,fd_set *fdset);
void FD_CLR(int fd,fd_set *fdset);
void FD_SET(int fd,fd_set *fdset);
void FD_ZERO(fd_set* fdset);
這些接口可實(shí)現(xiàn)為宏或者函數(shù)。調(diào)用FD_ZERO將一個fd_set變量的所有位設(shè)置為0.調(diào)用FD_SET設(shè)置描述符集中的一位。調(diào)用FD_CLR可以清除一位。我們可以調(diào)用FD_ISSET測試描述符集中的一個指定位是否已經(jīng)打開。我們要注意,在我們聲明了一個描述符集之后,必須調(diào)用FD_ZERO函數(shù)將這個描述符集置為0,然后再在其中設(shè)置我們關(guān)心的各個描述符的位。
上面說了那么多,我們來用用這幾個函數(shù)吧,在下面的程序中,我們用剛說的那幾個函數(shù)寫了一個簡單的客戶/服務(wù)器間通信模型,客戶向服務(wù)端發(fā)送數(shù)據(jù),服務(wù)端收到后再回顯給客戶端,我們來看看具體代碼:
server端:
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <assert.h> #include <unistd.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/socket.h> #define _BACKLOG_ 5 int fds[64]; static void usage(const char* arg) { printf("usage:%s [ip][poort]",arg); } static int startup(char *ip,int port) { assert(ip); int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } struct sockaddr_in local; local.sin_family=AF_INET; local.sin_port=htons(port); local.sin_addr.s_addr=inet_addr(ip); if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0) { perror("bind"); exit(2); } if(listen(sock,_BACKLOG_)<0) { perror("listen"); exit(3); } return sock; } int main(int argc,char* argv[]) { if(argc!=3) { usage(argv[0]); exit(1); } int port=atoi(argv[2]); char *ip=argv[1]; int listen_sock=startup(ip,port); int done=0; int new_sock=-1; struct sockaddr_in client; socklen_t len=sizeof(client); int max_fd; fd_set reads; fd_set writs; int i=0; int fds_num=sizeof(fds)/sizeof(fds[0]); for( ;i<fds_num;++i) { fds[i]=-1; } fds[0]=listen_sock; max_fd=fds[0]; while(!done) { FD_ZERO(&reads); FD_ZERO(&writs); FD_SET(listen_sock,&reads); struct timeval timeout={5,0}; for(i=1;i<fds_num;++i) { if(fds[i]>0) { FD_SET(fds[i],&reads); if(fds[i]>max_fd) { max_fd=fds[i]; } } } switch(select(max_fd+1,&reads,&writs,NULL,&timeout)) { case 0://超時 printf("select timeout\n"); break; case -1: perror("select"); break; default: { i=0; for(;i<fds_num;++i) { if(fds[i]==listen_sock&&FD_ISSET(fds[i],&reads)) {//監(jiān)聽套接字就緒 new_sock=accept(listen_sock,(struct sockaddr*)&client,&len); if(new_sock<0) { perror("accept"); continue; } printf("get a new connect...%d\n",new_sock); for(i=0;i<fds_num;++i) { if(fds[i]==-1) { fds[i]=new_sock; break; } } if(i==fds_num) { close(new_sock); } }//listen sock else if(fds[i]>0&&FD_ISSET(fds[i],&reads)) { char buf[1024]; ssize_t _s=read(fds[i],buf,sizeof(buf)-1); if(_s>0) { buf[_s]='\0'; printf("client : %s",buf); write(fds[i],buf,_s); } else if(_s==0) { printf("client quit..\n"); close(fds[i]); fds[i]=-1; } else{ } }//nomal socket else{ } } } break; } } return 0; }
下面是client端:
#include <stdio.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> void usage(const char* arg) { printf("%s [remote_ip][remote_port\n",arg); } int main(int argc,char *argv[]) { if(argc != 3) { usage(argv[0]); exit(0); } int port=atoi(argv[2]); char *ip=argv[1]; int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0) { perror("socket"); exit(1); } struct sockaddr_in remote; remote.sin_family=AF_INET; remote.sin_port=htons(port); remote.sin_addr.s_addr=inet_addr(ip); int ret=connect(sock,(struct sockaddr*)&remote,sizeof(remote)); char buf[1024]; while(1) { printf("please enter: "); fflush(stdout); ssize_t _s=read(0,buf,sizeof(buf)-1); buf[_s]='\0'; write(sock,buf,sizeof(buf)-1); _s=read(sock,buf,sizeof(buf)-1); //回顯 if(_s>0) { buf[_s]='\0'; printf("server-->client:%s",buf); } } return 0; }
上面的結(jié)果如下:
從上面的結(jié)果我我們可以看到,從client端發(fā)送的數(shù)據(jù),最后被server端hui顯給client端了,達(dá)到了我們的目的。
當(dāng)前文章:select---基于TCP客戶/服務(wù)端編程
網(wǎng)站URL:http://aaarwkj.com/article32/igjssc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、云服務(wù)器、App設(shè)計、靜態(tài)網(wǎng)站、面包屑導(dǎo)航、網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)