Linux IO模型漫谈(5)- IO复用模型之select

简介:

首先需要了解的是select函数:

select函数

#include<sys/select.h>

#include<sys/time.h>

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

返回:就绪描述字的正数目,0——超时,-1——出错

 

参数解释:

maxfd: 最大的文件描述符(其值应该为最大的文件描述符字 + 1)

readset: 内核读操作的描述符字集合

writeset:内核写操作的描述符字集合

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进行读监听



本文转自轩脉刃博客园博客,原文链接:http://www.cnblogs.com/yjf512/archive/2012/06/07/2539755.html,如需转载请自行联系原作者

相关文章
|
2月前
|
网络协议 安全 Linux
Linux C/C++之IO多路复用(select)
这篇文章主要介绍了TCP的三次握手和四次挥手过程,TCP与UDP的区别,以及如何使用select函数实现IO多路复用,包括服务器监听多个客户端连接和简单聊天室场景的应用示例。
98 0
|
2月前
|
存储 Linux C语言
Linux C/C++之IO多路复用(aio)
这篇文章介绍了Linux中IO多路复用技术epoll和异步IO技术aio的区别、执行过程、编程模型以及具体的编程实现方式。
105 1
Linux C/C++之IO多路复用(aio)
|
2月前
|
Linux C++
Linux C/C++之IO多路复用(poll,epoll)
这篇文章详细介绍了Linux下C/C++编程中IO多路复用的两种机制:poll和epoll,包括它们的比较、编程模型、函数原型以及如何使用这些机制实现服务器端和客户端之间的多个连接。
35 0
Linux C/C++之IO多路复用(poll,epoll)
|
2月前
|
Java Linux
【网络】高并发场景处理:线程池和IO多路复用
【网络】高并发场景处理:线程池和IO多路复用
58 2
|
1月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
92 8
|
1月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
251 6
|
1月前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
80 3
|
1月前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
71 2
|
14天前
|
Linux Shell
Linux 10 个“who”命令示例
Linux 10 个“who”命令示例
43 14
Linux 10 个“who”命令示例
|
3天前
|
Ubuntu Linux
Linux 各发行版安装 ping 命令指南
如何在不同 Linux 发行版(Ubuntu/Debian、CentOS/RHEL/Fedora、Arch Linux、openSUSE、Alpine Linux)上安装 `ping` 命令,详细列出各发行版的安装步骤和验证方法,帮助系统管理员和网络工程师快速排查网络问题。
53 20
下一篇
DataWorks