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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

select服务器

發布時間:2024/4/11 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 select服务器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?select介紹


我們先來看一下select的接口。


? ? ? ?int select(int nfds, fd_set *readfds, fd_set *writefds,

? ? ? ? ? ? ? ? ? fd_set *exceptfds, struct timeval *timeout);



1

2

3

4

5

1

2

3

4

5

從上面的這些接口我們應該能有寫認識,首先我么來看select系統調用的參數的含義。


參數 功能

nfds 被監聽的文件描述符的總數。通常是文件描述符最大值加1

readfds 可讀事件的文件描述符集合

writefds 可寫事件的文件描述符集合

exceptfds 異常事件的文件描述符集合

timeout 設定超時時間

值得注意的是,后面的三個參數即是輸入型參數,又是輸出型參數,輸入表示關心那些文件描述符對應的特定事件發生。輸出表示的是那些文件描述符對應的事件就緒。當就緒后,內核將會去修改這些文件描述符的集合。這三個參數都是fd_set結構體類型


typedef struct

{

? ? /*XPG4.2requiresthismembername.Otherwiseavoidthename

? ? fromtheglobalnamespace.*/

? ? #ifdef__USE_XOPEN

? ? __fd_maskfds_bits[__FD_SETSIZE/__NFDBITS];

? ? #define__FDS_BITS(set)((set)->fds_bits)

? ? #else

? ? __fd_mask__fds_bits[__FD_SETSIZE/__NFDBITS];

? ? #define__FDS_BITS(set)((set)->__fds_bits)

? ? #endif

}fd_set;

1

2

3

4

5

6

7

8

9

10

11

12

13

1

2

3

4

5

6

7

8

9

10

11

12

13

可以看出fd_set就是一個結構體數組,這個結構體數組的每一位就是一個文件描述符的標記,配套提供了一些對于fd_set操作的宏。


? ? ? ?void FD_CLR(int fd, fd_set *set);

? ? ? ?int ?FD_ISSET(int fd, fd_set *set);

? ? ? ?void FD_SET(int fd, fd_set *set);

? ? ? ?void FD_ZERO(fd_set *set);

1

2

3

4

1

2

3

4

功能

FD_CLR 進行對應位fd

FD_ISSET 進行判斷對應位fd

FD_SET 設置fd的對應位置

FD_ZERO 進行清空fd_set

最后要說一下的就是timeout參數,這個參數用來設置超時時間,它也是一個結構體,它用來告訴應用程序select等待多久,這里的單位是微秒級別的。


timeout參數 說明

0 立即返回,即輪詢

NULL 阻塞監視文件描述符,當有時間就緒才返回

大于0的時間 超時時間設置

select調用時內核級別的,select的輪詢方式是和非阻塞輪詢方式是不同的,select的輪詢方式是同時可以對多個I/O端口進行監聽,任何一個端口數據好了,這個時候就可以讀了。然后通過系統調用,就可以把數據從內核拷貝到用戶進程。


![enter description here][1]


select缺點


1、 單個進程可監視的fd數量被限制,即能監聽端口的大小有限。


? 一般來說這個數目和系統內存關系很大,具體數目可以cat /proc/sys/fs/file-max查看,有宏FD_SETSIZE進行限制fd的數量。32位機默認是1024個。64位機默認是2048.

2、 對socket進行掃描時是線性掃描,即采用輪詢的方法,效率較低:


? ?當套接字比較多的時候,每次select()都要通過遍歷FD_SETSIZE個Socket來完成調度,不管哪個Socket是活躍的,都遍歷一遍。這會浪費很多CPU時間。如果能給套接字注冊某個回調函數,當他們活躍時,自動完成相關操作,那就避免了輪詢,這正是epoll與kqueue做的。

3、需要維護一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時復制開銷大


select代碼示例:


??6 #include<sys/socket.h> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? 7 #include<sys/types.h>

? 8 #include<netinet/in.h>

? 9?

?10 void usage(const char* str)

?11 {

?12 ? ? printf("usage:%[local_IP] [localP_port]\n",str);

?13 }

?14?

?15?

?16 int startup(char* IP, int port)

?17 {

?18 ? ?int ?sock=socket(AF_INET,SOCK_STREAM,0);

?19 ? ?if(sock<0){

?20 ? ? ? ?perror("sock");

?21 ? ? ? ?exit(2);

?22 ? ? ? ?}

?23?

?24 ? ? ? ?struct sockaddr_in ser_addr;

?25 ? ? ? ?ser_addr.sin_family=AF_INET;

?26 ? ? ? ?ser_addr.sin_port=htons(port);

?27 ? ? ? ?ser_addr.sin_addr.s_addr=inet_addr(IP);

?28 ? ? ? ?if(bind(sock,(struct sockaddr*)&ser_addr,sizeof(ser_addr))<0){

?29 ? ? ? ? ? ?perror("bind");

?30 ? ? ? ? ? ?exit(3);

?31 ? ? ? ? ? ?}

?32 ? ? ? ??

?33 ? ? ? ? ? ?if(ret<0){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

?34 ? ? ? ? ? ? ? ?perror("listen");

?35 ? ? ? ? ? ? ? ?exit(4);

?36 ? ? ? ? ? ? ? ?}

?37 ? ? ? ? ? ? ? ?return sock;

?38 }

?39 ?int array_fds[1024];

?40 ?int maxfd;

?41?

?42?

?43 int main(int argc, char* argv[])

?44 {

?45 ? ? if(argc!=3){

?46 ? ? ? ? usage(argv[0]);

?47 ? ? ? ? exit(0);

?48 ? ? ? ? }

?49?

?50 ? ? ? ? int listen_sock=startup(argv[1],atoi(argv[2]));

?51 ? ? ? ? int i=0;

?52 ? ? ? ? for(;i<1024;i++){

?53 ? ? ? ? ? ? array_fds[i]=-1;

?54 ? ? ? ? ? ? }

?55?

?56 ? ? ? ? ? ? array_fds[0]=listen_sock;

?57 ? ? ? ? ? ? fd_set reads;

?58 ? ? // ? ? ?fd_set writes;

?59 ? ? ? ? ? ? struct timeval timeout;

?60 ? ? ? ? ? ? while(1){

?61 ? ? ? ? ? ? ? ? FD_ZERO(&reads);

-- INSERT -- ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?33,1 ? ? ? ? ?28%


60 ? ? ? ? ? ? while(1){ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?61 ? ? ? ? ? ? ? ? FD_ZERO(&reads);
?62 ? ? // ? ? ? ? ?FD_ZERO(&writes);
?63 ? ? ? ? ? ? ? ? int maxfd=0;
?64 ? ? ? ? ? ? ? ? timeout.tv_sec=10;
?65 ? ? ? ? ? ? ? ? timeout.tv_usec=0;
?66?
?67 ? ? ? ? ? ? ? ? for(i=0;i<1024;i++){
?68 ? ? ? ? ? ? ? ? // ?if(array_fds[i]>0){
?69 ? ? ? ? ? ? ? ? // ? ? ?FD_SET(array_fds[i],&reads);
?70 ? ? ? ? ? ? ? ? // ? ? ?FD_SET(array_fds[i],&writes);
?71 ? ? ? ? ? ? ? ? ? ?if(array_fds[i]==-1){
?72 ? ? ? ? ? ? ? ? ? ? ? ?continue;
?73 ? ? ? ? ? ? ? ? ? ? ? ?}
?74 ? ? ? ? ? ? ? ? ? ? ? ?FD_SET(array_fds[i],&reads);
?75 ? ? ? ? ? ? ? ? ? ? ? ? if(array_fds[i]>maxfd){
?76 ? ? ? ? ? ? ? ? ? ? ? ? ? ? maxfd=array_fds[i];
?77 ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
?78 ? ? ? ? ? ? ? ? ? ? ? ? }//FD
?79 ? ? ? ? ? ? ? ? ? ? }//for
?80 ? ? ? ? ? ? ? ? ? ? int j=0;
?81 ? ? ? ? ? ? ? ? ? ? switch(select(maxfd+1,&reads,/*&writes*/NULL,NULL,&timeout)){
?82 ? ? ? ? ? ? ? ? ? ? ? ? case 0:
?83 ? ? ? ? ? ? ? ? ? ? ? ? printf("time quit.....\n");
?84 ? ? ? ? ? ? ? ? ? ? ? ? break;
?85 ? ? ? ? ? ? ? ? ? ? ? ? case -1:
?86 ? ? ? ?

86 ? ? ? ? ? ? ? ? ? ? ? ? perror("select");
?87 ? ? ? ? ? ? ? ? ? ? ? ? break;
?88 ? ? ? ? ? ? ? ? ? ? ? ? default:{
?89 ? ? ? ? ? ? ? ? ? ? ? ? for(j=0;j<1024;j++){
?90 ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(array_fds[j]<0){
?91 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue;
?92 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
?93 ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(j==0&&FD_ISSET(array_fds[0],&reads)){
?94 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? struct sockaddr_in client;
?95 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? socklen_t len=sizeof(client);
?96 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int new_sock=accept(array_fds[0],(struct sockaddr *)&client,&len);
?97 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(new_sock<0){
?98 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? perror("accept");
?99 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue;
100 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
101?
102 ? ? ?printf("get a new client :(%s:%d)\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
103 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int k=1;
104 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? for(;k<1024;k++){
105 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(array_fds[k]<0)
106 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
107 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
108 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
109 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
110 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(j==1024){
111 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("client full\n");
112 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? close(new_sock);
113 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
114 ? ? ? ? ? ? ? ??

114 ? ? ? ? ? ? ? ? ? ? ? ? ? ? }else{

115 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(j!=0&&FD_ISSET(array_fds[j],&reads)){
116 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("***read start***");
117 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? char buf[1024];
118 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ssize_t s=read(array_fds[j],buf,sizeof(buf)-1);
119 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if(s<0){
120 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? perror("read");
121 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? close(array_fds[j]);
122 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? array_fds[j]=-1;
123 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
124 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }else if(s==0){
125 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("client quit...\n");
126 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? close(array_fds[j]);
127 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? array_fds[j]=-1;
128?
129 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }else {
130 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? buf[s]=0;
131 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("client # ?%s\n",buf);
132 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
133 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }else{
134?
135 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
136 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
137 ? ? ? ? ? ? ? ? ? ? ? ? }
138 ? ? ? ? ? ? ? ? ? ? ? ? break;
139 ? ? ? ? ? ? ? ? }//while
140 ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
141 ? ? ? ? ? ? ? ? ? ? ? ? ? ? return 0;

142 } ? ? ? ?


select優點:

1.一次可以等待多個文件描述符,減少了平均等待時間

2.客戶越來越多時,減輕了進程調度的壓力(相較于多進程多線程服務器)

select缺點:

1.能監聽的文件描述符有上限,這個上限是由fd_set決定的。

2.它返回的只是就緒事件的個數,要判斷是那個事件滿足,需要遍歷文件描述符。

3.select監聽的集合是輸入輸出參數,每次監聽都需要重新初始化。

4.每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大

5.內核采用輪詢(遍歷fd集合)的方式來檢測就緒事件,這個開銷在fd很多時也很大

6.select和poll都只能工作在低效的LT(水平觸發)模式

?? ??

總結

以上是生活随笔為你收集整理的select服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。