unix下網絡編程之I/O複用(四)

首先須要瞭解的是select函數:java

select函數

#include<sys/select.h>服務器

#include<sys/time.h>socket

int select (int maxfd , fd_set *readset ,fd_set *writeset, fd_set *exceptionset , const struct timeval * timeout);函數

返回:就緒描述字的正數目,0——超時,-1——出錯spa

 

參數解釋:指針

maxfd: 最大的文件描述符(其值應該爲最大的文件描述符字 + 1)code

readset: 內核讀操做的描述符字集合server

writeset:內核寫操做的描述符字集合blog

exceptionset:內核異常操做的描述符字集合事件

timeout:等待描述符就緒須要多少時間。NULL表明永遠等下去,一個固定值表明等待固定時間,0表明根本不等待,檢查描述字以後當即返回。

 

注意:readset,writeset,exceptionset都是值-結果參數,意思就是他們傳進入指針進去,函數根據指針能夠修改對應的fd_set

 

fd_set集合操做

fd_set和名字同樣,是一個描述符的集合。有下面幾個操做:

void FD_ZERO(fd_set *fdset); /* 將全部fd清零 */

void FD_SET(int fd, fd_set *fdset); /* 增長一個fd */

void FD_CLR(int fd, fd_set *fdset); /* 刪除一個fd */

int FD_ISSET(int fd, fd_set *fdset); /* 判斷一個fd是否有設置 */

咱們如今要作一個select使用的server,server監聽兩個端口(7778和7779)的socket。再使用兩個cli,一個client鏈接到7778端口,另外一個client鏈接到7779端口。

 

服務器端代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
 
int  main( int  argc, char  *argv[])
{
     //這個服務器同時監聽7777和7778兩個端口
     
     //綁定監聽7779端口的fd
     int  listenfd1;
     struct sockaddr_in serv_addr1;
     listenfd1 = socket(AF_INET, SOCK_STREAM, 0 );
     
     bzero(( char  *) &serv_addr1, sizeof(serv_addr1));
     serv_addr1.sin_family = AF_INET;
     serv_addr1.sin_port = htons( 7777 );
     serv_addr1.sin_addr.s_addr = INADDR_ANY;
     
     bind(listenfd1, (struct sockaddr *) &serv_addr1, sizeof(serv_addr1));
     listen(listenfd1, 5 );
     
     //綁定監聽7778端口的fd
     int  listenfd2;
     struct sockaddr_in serv_addr2;
     listenfd2 = socket(AF_INET, SOCK_STREAM, 0 );
     
     bzero(( char  *) &serv_addr2, sizeof(serv_addr2));
     serv_addr2.sin_family = AF_INET;
     serv_addr2.sin_port = htons( 7778 );
     serv_addr2.sin_addr.s_addr = INADDR_ANY;
     
     bind(listenfd2, (struct sockaddr *) &serv_addr2, sizeof(serv_addr2));
     listen(listenfd2, 5 );
     
     
     int  maxfd;
     //爲何這裏設置兩個fd_set?每次select的時候函數會把沒有事件發生的描述字清零,因此須要兩個集合
     fd_set allset, rset;
     maxfd = listenfd1;
     if (listenfd2 > maxfd) {
         maxfd = listenfd2;
     }
     
     FD_ZERO(&allset);
     FD_SET(listenfd1, &allset);
     FD_SET(listenfd2, &allset);
     
     int  clifd, clilen;
     struct sockaddr_in cli_addr;
     char  buffer[ 256 ];
     for (;;) {
         rset = allset;
         select(maxfd + 1 , &rset, NULL, NULL, NULL);
         
         //若是是listenfd1 獲取消息
         if (FD_ISSET(listenfd1, &rset)) {
             clilen = sizeof(cli_addr);
             clifd = accept(listenfd1, (struct sockaddr *) &cli_addr, &clilen);
             
             bzero(buffer, 256 );
             read(clifd, buffer, 255 );
             printf( "Listenfd1 Message is:%s\r\n" , buffer);
         }
         
         //若是是listenfd1 獲取消息
         if (FD_ISSET(listenfd2, &rset)) {
             clilen = sizeof(cli_addr);
             clifd = accept(listenfd2, (struct sockaddr *) &cli_addr, &clilen);
             
             bzero(buffer, 256 );
             read(clifd, buffer, 255 );
             printf( "Listenfd2 Message is:%s\r\n" , buffer);
         }
         close(clifd);
     }
     
     close(listenfd1);
     close(listenfd2);
 
     return  0 ;
}

客戶端1 代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
 
int  main( int  argc, char * argv[])
{
     int  socketfd, n;
     socketfd = socket(AF_INET, SOCK_STREAM, 0 );
     
     struct sockaddr_in serv_addr;
         
     bzero(( char  *)&serv_addr, sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_port = htons( 7778 );
         
     connect(socketfd,(struct sockaddr *)  &serv_addr, sizeof(serv_addr));
         
     write(socketfd, "client message" , 14 );
     return  0 ;
 
}

客戶端2代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
 
int  main( int  argc, char * argv[])
{
     int  socketfd, n;
     socketfd = socket(AF_INET, SOCK_STREAM, 0 );
     
     struct sockaddr_in serv_addr;
         
     bzero(( char  *)&serv_addr, sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_port = htons( 7779 );
         
     connect(socketfd,(struct sockaddr *)  &serv_addr, sizeof(serv_addr));
         
     write(socketfd, "client message" , 14 );
     return  0 ;
 
}

調用步驟:

1 啓動服務器端

2 啓動客戶端1

3 啓動客戶端2

4 服務器端表

 

客戶端啓動:

clip_image001

服務端表現:

clip_image002

這裏就是使用select函數對多個socket進行讀監聽

相關文章
相關標籤/搜索