io复用select方法编写的服务器
- 摘要:io多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般都是读就绪或者写就绪),就能通知应用程序进行相应的读写操作。select函数作为io多路复用的机制,第一个参数nfds是fd_set集合中最大描述符值+1,fdset是一个位数组,每一位代表其对应的描述符是否需要被检查。第二三四参数表示需要关注读、写、错误时间的文件描述符位数组,这些参数既是输入型参数也是输出型参数,可能会被内核修改用于标识哪些描述符上发生了关注的事件,所以每次调用select前都需要重新
io多路复用是通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般都是读就绪或者写就绪),就能通知应用程序进行相应的读写操作。select函数作为io多路复用的机制,第一个参数nfds是fd_set集合中最大描述符值+1,fdset是一个位数组,每一位代表其对应的描述符是否需要被检查。第二三四参数表示需要关注读、写、错误时间的文件描述符位数组,这些参数既是输入型参数也是输出型参数,可能会被内核修改用于标识哪些描述符上发生了关注的事件,所以每次调用select前都需要重新初始化fdset。timeout参数为超时时间,该结构会被内核修改,其值为超时剩余时间。
select函数返回值有三种,返回-1时表示select失败;返回0表示超时;其他返回值表示select成功。
2018-12-02 18:56:42
#include<stdio.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<stdlib.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
int rfds[];
void usage(const char* proc)
{
assert(proc);
printf("usage:%s: [ip] [port]/n",proc);
}
int start_up(const char* ip,int port)
{
assert(ip);
assert(port > );
int sock = socket(AF_INET,SOCK_STREAM,);
if(sock < )
{
perror("socket");
exit();
}
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons(port);
local.sin_addr.s_addr =inet_addr(ip);
if(bind(sock,(struct sockaddr*)&;local,sizeof(local)) < )
{
perror("bind");
exit();
} if(listen(sock,) < )
{
perror("listen");
exit();
}
return sock;
}
int main(int argc,char* argv[])
{
if(argc != )
{
usage(argv[]);
return ;
}
int listen_sock = start_up(argv[],atoi(argv[]));
for(int i= ;i < ; i++)
{
rfds[i] = -;
}
fd_set rset;
int max_fd = ;
while()
{
struct timeval timeout = {,};
FD_ZERO(&;rset);
rfds[] = listen_sock;
max_fd = listen_sock;
for(int i= ;i < ; i++)
{
if(rfds[i] >= )
{
FD_SET(rfds[i],&;rset);
if(max_fd < rfds[i])
max_fd = rfds[i];
}
}
switch(select(max_fd + ,&;rset,NULL,NULL,NULL))
{
case -:
perror("select");
break;
case :
printf("timeout");
break;
default:
{
int j = ;
for(;j < ;j++)
{
if(rfds[j] < )
continue;
if(j == &;&;FD_ISSET(rfds[j],&;rset))
{
struct sockaddr_in client;
socklen_t len = sizeof(client);
int new_fd = accept(listen_sock,(struct sockaddr*)&;client,&;len);
if(new_fd < )
{
perror("accept");
}
else
{
printf("get a client:socket :%s:%d/n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
int k = ;
for(;k < ;k++)
{
if(rfds[k] == -)
{
rfds[k] = new_fd; break;
}
}
if( k == )
{
close(new_fd);
}
}
}
else if(FD_ISSET(rfds[j],&;rset))
{
char buf[];
ssize_t s = read(rfds[j],buf,sizeof(buf)-);
if(s > )
{
buf[s] = ;
printf("client#%s/n",buf);
}
else if(s == )
{
printf("client close.../n");
close(rfds[j]); rfds[j] = -;
}
else
{
perror("read");
}
}
}
}
break;
}
}
}
select_server.c
使用telnet为一个客户端访问:

当把服务器终止后,再次打开服务器会出现这种情况:

这是因为,虽然server的应用程序终止了,但tcp协议层的连接没有完全断开,因此不能再次监听同样的server端口。
client终止时自动关闭socket描述符,server的TCP连接收到client发的FIN段后处于TIME_WAIT状态。TCP协议规定,主动关闭连接的一方要处于TIME_WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态,因为我们先Ctrl-C终止了server,所以server是主动关闭连接的一方,在TIME_WAIT期间仍然不能再次监听同样的server端口。MSL在RFC1122中规定为两分钟,但是各操作系统的实现不同,在Linux上一般经过半分钟后 就可以再次启动server了。
io复用select方法编写的服务器的更多相关文章
- IO复用——select系统调用
1.select函数 此函数用于在一段时间内,监听用户感兴趣的文件描述符上的可读.可写和异常等事件. #include<sys/select.h> int select(int nfds, ...
- IO复用: select 和poll 到epoll
linux 提供了select.poll和epoll三种接口来实现多路IO复用.下面总结下这三种接口. select 该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经 ...
- Linux IO多路复用 select
Linux IO多路复用 select 之前曾经写过简单的服务器,服务器是用多线程阻塞,客户端每一帧是用非阻塞实现的 后来发现select可以用来多路IO复用,就是说可以把服务器这么多线程放在一个线程 ...
- IO复用的三种方法(select,poll,epoll)深入理解
(一)IO复用是Linux中的IO模型之一,IO复用就是进程告诉内核需要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程处理,从而不会在单个IO上阻塞了,Linux中,提供 ...
- linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)
IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...
- 第十七篇:IO复用之select实现
前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识. 接下来,我要在一个具体的并发客户端中实现它(基于select函数),使得一旦服务器中的客户进程被终止的时候,客户端这 ...
- IO复用之select实现
前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识.接下来,我要在一个具体的并发客户端中实现它( 基于select函数 ),使得一旦服务器中的客户进程被终止的时候,客户端 ...
- 多路IO复用模型--select, poll, epoll
select 1.select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数 2.解决1024以下客户端时使用se ...
- IO复用(Reactor模式和Preactor模式)——用epoll来提高服务器并发能力
上篇线程/进程并发服务器中提到,提高服务器性能在IO层需要关注两个地方,一个是文件描述符处理,一个是线程调度. IO复用是什么?IO即Input/Output,在网络编程中,文件描述符就是一种IO操作 ...
随机推荐
- 微信小程序复选框实现 多选一功能
功能实现界面 data: { checkboxItems: [ { name: '全天(1-8节)', value: 'allday' }, { name: '上午(1-4节)', value: 'a ...
- EF的优缺点
优点: 1.简洁的Linq to Sql语句大大提高了开发人员的效率,不要再写复杂的sql语句: 2.不再需要再管应用程序如何去连接数据库: 3.EF可以用作用于数据服务和OData Service的 ...
- adb常用命令(转)
1.Android Debug Bridge -adb常用命令 1.1简介 Android Debug Bridge,我们一般简称为adb,主要存放在sdk安装目录下的platform-tools文件 ...
- Shiro 与spring 整合的及简单使用(转)
文章完全转载自: http://www.cnblogs.com/learnhow/p/5694876.html ,大家可以点击访问原文链接,个人仅作学习收藏 ! 本篇内容大多总结自张开涛的<跟 ...
- C#图像显示实现拖拽、锚点缩放功能【转】
1.图像拖拽 核心步骤: ①新建Point类型全局变量mouseDownPoint,记录拖拽过程中鼠标位置: ②MouseDown事件记录Cursor位置: ③MouseMove事件计算移动矢量,并更 ...
- 小程序tab切换 点击左右滑动
wxml <scroll-view scroll-x="true" class="navbar-box"> <block wx:for=&qu ...
- vue.js+webpack在一个简单实例中的使用过程demo
这里主要记录vue.js+webpack在一个简单实例中的使用过程 说明:本次搭建基于Win 7平台 Node.js 安装官网提供了支持多种平台的的LTS版本下载,我们根据需要来进行下载安装.对于Wi ...
- tortoisegit里的cleanup坑
tortoisegit的clean up功能(以下红框部分)真的不要去点啊,你所有被ignore(忽略)的本地文件会被全部删除,而且是无法恢复的,因为远程仓库里根本就没有这些文件. 血的教训啊,本以为 ...
- JQuery的常用选择器 转
JQuery的常用选择器 刚开始学JQuery写的如有错误欢迎批评指正 JQuery拥有的选择器可以让我们更快更方便找到想要的元素,然后对相应的元素进行操作 简单介绍一下一些常用的选择器: 1.基本选 ...
- webpack打包vue项目,资源路径如何从绝对路径改为相对路径?css中的图片资源如何修改配置?
资源相对引用路径 问题描述 一般情况下,通过webpack+vuecli默认打包的css.js等资源,路径都是绝对的. 但当部署到带有文件夹的项目中,这种绝对路径就会出现问题,因为把配置的static ...