博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
select - I/O多路复用
阅读量:6592 次
发布时间:2019-06-24

本文共 2978 字,大约阅读时间需要 9 分钟。

使用select函数的套接字

如果你想保持现有连接的同时,侦听新的连接,怎么办呢?
普通的做法(使用recv, accept是做不到的)。当使用accetp等待新的连接时,程序是阻塞的,也就没办法再同原有连接保持通信。
另一种做法是,使用非阻塞方式,但这会浪费了宝贵的CPU时间(你的不停的轮询轮询)。
有没有更好的办法呢?答案是肯定的 – 使用select函数。
select可以帮助你同时监听多个套接字。它会告诉你哪个套接字读数据就绪, 哪个套接字写数据就绪,哪个套接字发生错误。
使用select意味着使用I/O多路技术。

select函数头文件:

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

select函数原型:

int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
详细信息可查看 man select
select()函数的参数说明:
numfds 是readfds,writefds,exceptfds 中fd 集合中文件描述符中最大的数字加上1。
readfds 中的fd 集合将由select 来监视是否可以读取。
writefds 中的fds 集合将由select 来监视是否可以写入。
exceptfds 中的fds 集合将由select 来监视是否有例外发生。
timeout 是用来设置等待超时的
返回值:
如果成功,则返回就绪的文件描述符的数量。超时一般返回0。错误返回-1。
这个timeval 结构定义如下:
struct timeval
{
int tv_sec ; /* 秒数 */
int tv_usec ; /* 微秒 */
} ;
只需要将tv_sec 设置为你想等待的秒数,然后设置tv_usec 为想等待的微秒数(真正
的时间就是tv_sec 所表示的秒数加上tv_usec 所表示的微秒数)。当select()函数返回的时候,timeval 中的时间将会被设置为执行为select()后还剩下的时间。

如果你想知道是是否可以从标准输入和一些套接字(sockfd)中读取数据,你就可以把文件描述符和sockfd 加入readfds 中。numfds 的数值设成readfds 中文件描述符中最大的那个加上一,也就是sockfd+1(因为标准输入的文件描述符的值为0 ,所以其他任何的文件描述符都会比标准输入的文件描述符大)。
当select()函数返回的时候,readfds 将会被修改用来告诉你哪一个文件描述符你可以用来读取数据。使用FD_ISSET() 宏,你可以选出select()函数执行的结果。

处理fd_set的宏:

FD_ZERO(fd_set *set)将一个文件描述符集合清零
FD_SET(int fd, fd_set *set)将文件描述符fd 加入集合set 中 – 这样select就会去监听它的状态。
FD_CLR(int fd, fd_set *set)将文件描述符fd 从集合set 中删除 – select不再去监听它的状态。
FD_ISSET(int fd, fd_set *set)检测fd在fdset集合中的状态是否变化。当检测到fd状态发送变化时返回真,否则,返回假。

下面程序,等待从标准输入输入数据,并打印所输入的数据。如果3秒内没输入(输入回车才算输入就绪),则打印超时或出错。

View Code
#include 
#include
#include
#include
int main(int argc, char **argv){ fd_set fdsets; FD_ZERO(&fdsets); FD_SET(STDIN_FILENO, &fdsets); struct timeval timeout; timeout.tv_sec = 5; timeout.tv_usec = 0; char buff[50]; if (select(2, &fdsets, NULL, NULL, &timeout)>0) { if (FD_ISSET(STDIN_FILENO, &fdsets)) { scanf("%s", buff); printf("has input\n"); } } else { printf("timeout or error!\n"); } return 0;}

下面是使用select同时侦听多个连接的例子:

View Code
#include
#include
#include
#include
#include
#define PORT 1234#define MAXSOCKFD 10int main(int argc, char **argv){ int sockfd,newsockfd,is_connected[MAXSOCKFD],fd; struct sockaddr_in addr; int addr_len = sizeof(struct sockaddr_in); fd_set readfds; char buffer[256]; char msg[ ] ="Welcome to server!"; if ((sockfd = socket(AF_INET,SOCK_STREAM,0))<0) { perror("socket"); exit(1); } bzero(&addr,sizeof(addr)); addr.sin_family =AF_INET; addr.sin_port = htons(PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sockfd,&addr,sizeof(addr))<0) { perror("connect"); exit(1); } if(listen(sockfd,3)<0) { perror("listen"); exit(1); } for(fd=0;fd

转载地址:http://sazio.baihongyu.com/

你可能感兴趣的文章
华丽的设计,20个免费的图标字体
查看>>
任意不规则形状的图片剪裁 .
查看>>
asp.net负载均衡方案[转]
查看>>
利用备份技术获取apk本地存储数据
查看>>
【POJ】3133 Manhattan Wiring
查看>>
VB中的冒号——bug
查看>>
微软职位内部推荐-Software Development Engineer 2
查看>>
mysql触发器使用实例
查看>>
工作流和审批流
查看>>
使用JPedal取代PDFBox
查看>>
uva--562Dividing coins +dp
查看>>
underscore 1.7.0 api
查看>>
C# CheckedListBox控件的使用方法
查看>>
spring Transaction Management --官方
查看>>
jar的打包与共享
查看>>
iOS开发-清理缓存功能的实现
查看>>
linux----关于定位和查找
查看>>
ci创建zip
查看>>
IS_ERR、PTR_ERR、ERR_PTR
查看>>
html5 canvas 奇怪的形状垂直渐变
查看>>