- 💂 个人主页:努力学习的少年
- 🤟 版权: 本文由【努力学习的少年】原创、在CSDN首发、需要转载请联系博主
- 💬 如果文章对你有帮助、欢迎关注、点赞、收藏(一键三连)和订阅专栏哦
目录
select函数是IO多路复用的函数,它主要的功能是用来等文件描述符中的事件是否就绪,select可以使我们在同时等待多个文件缓冲区 ,减少IO等待的时间,能够提高进程的IO效率。
select()函数允许程序监视多个文件描述符,等待所监视的一个或者多个文件描述符变为“准备好”的状态。所谓的”准备好“状态是指:文件描述符不再是阻塞状态,可以用于某类IO操作了,包括可读,可写,发生异常三种
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
等待的文件描述符的最大值+1,例如:应用进程想要去等待文件描述符3,5,8的事件,则
nfds=max(3,5,8)+1;
readfds和writefds,exceptfds的类型都是fd_set,那么fd_set类型是什么呢?

与readfds类似,writefds是等待写事件(缓冲区中是否有空间)的集合,如果不关心写事件,则可以传值NULL。
如果内核等待相应的文件描述符发生异常,则将失败的文件描述符设置进exceptfds中,如果不关心错误事件,可以传值NULL。
设置select在内核中阻塞的时间,如果想要设置为非阻塞,则设置为NULL。如果想让select阻塞5秒,则将创建一个struct timeval time={5,0};
其中struct timeval的结构体类型是:
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
应用进程和内核都需要从readfds和writefds获取信息,其中,内核需要从readfds和writefds知道哪些文件描述符需要等待,应用进程需要从readfds和writefds中知道哪些文件描述符的事件就绪.

如果我们要不断轮询等待文件描述符,则应用进程需要不断的重新设置readfds和writefds,因为每一次调用select,内核会修改readfds和writefds,所以我们需要在 应用程序 中 设置一个数组 来保存程序需要等待的文件描述符,保证调用 select 的时候readfds 和 writefds中的将如下:

如果是一个select服务器进程,则服务器进程会不断的接收有新链接,每个链接对应一个文件描述符,如果想要我们的服务器能够同时等待多个链接的数据的到来,我们监听套接字listen_sock读取新链接的时候,我们需要将新链接的文件描述符保存到read_arrys数组中,下次轮询检测的就会将新链接的文件描述符设置进readfds中,如果有链接关闭,则将相对应的文件描述符从read_arrys数组中拿走。
一张图看懂select服务器:

简易版的select服务器:
server.hpp文件:
#pragma once
#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
using std::cout;
using std::endl;
#define BACKLOG 5
namespace sjp{
class server{
public:
static int Socket(){
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock>0)
return sock;
if(sock<0)
exit(-1);
W> }
static bool Bind(int sockfd,short int port){
struct sockaddr_in lock;
memset(&lock,'\0',sizeof(lock));
lock.sin_family=AF_INET;
lock.sin_port=htons(port);
lock.sin_addr.s_addr=INADDR_ANY;
if(bind(sockfd,(struct sockaddr*)&lock,(socklen_t)sizeof(lock))<0){
exit(-2);
}
return true;
}
static bool Listen(int sockfd){
if(listen(sockfd,BACKLOG)<0){
exit(-3);
}
return true;
}
};
}
select_server.hpp文件
#pragma once
#include<vector>
#include"server.hpp"
#include<unistd.h>
#include<time.h>
namespace Select{
class select_server{
private:
int listen_sock;//监听套接字
int port;
public:
select_server(int _port):port(_port){}
//初始化select_server服务器
void InitServer(){
listen_sock=sjp::server::Socket();
sjp::server::Bind(listen_sock,port);
sjp::server::Listen(listen_sock);
}
void Run(){
std::vector<int> readfds_arry(1024,-1);//readfds_arry保存读事件的文件描述符
readfds_arry[0]=listen_sock;//将监听套接字保存进readfds_arry数组中
fd_set readfds;
while(1){
FD_ZERO(&readfds);
int nfds=0;
//将read_arry数组中的文件描述符设置进程readfds_arry位图中
for(int i=0;i<1024;i++)
{
if(readfds_arry[i]!=-1){
FD_SET(readfds_arry[i],&readfds);
if(nfds<readfds_arry[i]){
nfds=readfds_arry[i];
}
}
}
//调用select对readfds中的文件描述符进行等待数据
switch(select(nfds+1,&readfds,NULL,NULL,NULL)){
case 0:
//没有一个文件描述符的读事件就绪
cout<<"select timeout"<<endl;
break;
case -1:
//select失败
cout<<"select error"<<endl;
default:
{
//有读事件发生
Soluation(readfds_arry,readfds);
break;
}
}
}
}
void Soluation(std::vector<int>& readfds_arry,fd_set readfds){
W> for(int i=0;i<readfds_arry.size();i++){
if(FD_ISSET(readfds_arry[i],&readfds))
{
if(readfds_arry[i]==listen_sock){
//有新链接到来
struct sockaddr peer;
socklen_t len;
int newfd=accept(listen_sock,&peer,&len);
cout<<newfd<<endl;
//将新链接设置进readfds_arry数组中
AddfdsArry(readfds_arry,newfd);
}
else{
//其他事件就绪
char str[1024];
int sz=recv(readfds_arry[i],&str,sizeof(str),MSG_DONTWAIT);
switch(sz){
case -1:
//读取失败
cout<<readfds_arry[i]<<": recv error"<<endl;
break;
case 0:
//对端关闭
readfds_arry[i]=-1;
cout<<"peer close"<<endl;
break;
default:
str[sz]='\0';
cout<<str<<endl;
break;
}
}
}
}
}
void AddfdsArry(std::vector<int>& fds_arry,int fd){
W> for(int i=0;i<fds_arry.size();i++){
if(fds_arry[i]==-1){
fds_arry[i]=fd;
break;
}
}
}
};
}
select_server.cc文件
#include"select_server.hpp"
int main(int argv,char* argc[]){
if(argv!=2){
cout<<"./selectserver port"<<endl;
exit(-4);
}
int port=atoi(argc[1]);//端口号
Select::select_server* sl=new Select::select_server(port);
sl->InitServer();
sl->Run();
}
测试:

关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
我正在尝试将以下SQL查询转换为ActiveRecord,它正在融化我的大脑。deletefromtablewhereid有什么想法吗?我想做的是限制表中的行数。所以,我想删除少于最近10个条目的所有内容。编辑:通过结合以下几个答案找到了解决方案。Temperature.where('id这给我留下了最新的10个条目。 最佳答案 从您的SQL来看,您似乎想要从表中删除前10条记录。我相信到目前为止的大多数答案都会如此。这里有两个额外的选择:基于MurifoX的版本:Table.where(:id=>Table.order(:id).
我有一个集合选择:此方法的单选按钮是什么?谢谢 最佳答案 Rails3中没有这样的助手。在Rails4中,它是collection_radio_buttons. 关于ruby-on-rails-rails上的ruby:radiobuttonsforcollectionselect,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/18525986/
date_select方法只能设置:start_year,但我想设置开始日期(例如3个月前的日期)(但没有这样的选项)。那么,我可以将开始日期设置为date_select方法吗?或者,要制作这样的选择框,我应该使用select_tag和options_for_select吗?或者,有什么解决办法吗?谢谢, 最佳答案 有可能……例如:start_year–设置年份选择的开始年份。默认为Time.now.year-5参见thisresource. 关于ruby-Rails3-我可以将开始日期
一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su
TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是
Linux操作系统——网络配置与SSH远程安装完VMware与系统后,需要进行网络配置。第一个目标为进行SSH连接,可以从本机到VMware进行文件传送,首先需要进行网络配置。1.下载远程软件首先需要先下载安装一款远程软件:FinalShell或者xhell7FinalShellxhell7FinalShell下载:Windows下载http://www.hostbuf.com/downloads/finalshell_install.exemacOS下载http://www.hostbuf.com/downloads/finalshell_install.pkg2.配置CentOS网络安装好
文章目录一基础定义二创建逻辑卷2-1准备物理设备2-2创建物理卷2-3创建卷组2-4创建逻辑卷2-5创建文件系统并挂载文件三扩展卷组和缩减卷组3-1准备物理设备3-2创建物理卷3-3扩展卷组3-4查看卷组的详细信息以验证3-5缩减卷组四扩展逻辑卷4-1检查卷组是否有可用的空间4-2扩展逻辑卷4-3扩展文件系统五删除逻辑卷5-1备份数据5-2卸载文件系统5-3删除逻辑卷5-4删除卷组5-5删除物理卷六LVM逻辑卷缩容6-1缩容注意事项6-2标准缩容步骤一基础定义LVM,LogicalVolumeManger,逻辑卷管理,Linux磁盘分区管理的一种机制,建立在硬盘和分区上的一个逻辑层,提高磁盘分
如何在Ruby中扩展date_select的范围??它只显示2005年,我想用它作为出生日期。 最佳答案 您可以使用:start_year选项,参见thedocumentation. 关于ruby-on-rails-date_selectruby,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/2047739/
如何在Ruby中获取linux系统(这必须适用于Fedora、Ubuntu等)的软件/硬件信息? 最佳答案 Chef背后的优秀人才,拥有一颗名为Ohai的优秀gemhttps://github.com/opscode/ohai以散列形式返回系统信息,例如操作系统、内核、规范、fqdn、磁盘、空间、内存、用户、接口(interface)、sshkey等。它非常完整,非常好。它还会安装命令行二进制文件(也称为ohai)。 关于ruby-如何在Ruby中获取linux系统信息,我们在Stack