• 摘要: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方法编写的服务器的更多相关文章

  1. IO复用——select系统调用

    1.select函数 此函数用于在一段时间内,监听用户感兴趣的文件描述符上的可读.可写和异常等事件. #include<sys/select.h> int select(int nfds, ...

  2. IO复用: select 和poll 到epoll

    linux 提供了select.poll和epoll三种接口来实现多路IO复用.下面总结下这三种接口. select 该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经 ...

  3. Linux IO多路复用 select

    Linux IO多路复用 select 之前曾经写过简单的服务器,服务器是用多线程阻塞,客户端每一帧是用非阻塞实现的 后来发现select可以用来多路IO复用,就是说可以把服务器这么多线程放在一个线程 ...

  4. IO复用的三种方法(select,poll,epoll)深入理解

    (一)IO复用是Linux中的IO模型之一,IO复用就是进程告诉内核需要监视的IO条件,使得内核一旦发现进程指定的一个或多个IO条件就绪,就通过进程处理,从而不会在单个IO上阻塞了,Linux中,提供 ...

  5. linux基础编程:IO模型:阻塞/非阻塞/IO复用 同步/异步 Select/Epoll/AIO(转载)

      IO概念 Linux的内核将所有外部设备都可以看做一个文件来操作.那么我们对与外部设备的操作都可以看做对文件进行操作.我们对一个文件的读写,都通过调用内核提供的系统调用:内核给我们返回一个file ...

  6. 第十七篇:IO复用之select实现

    前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识. 接下来,我要在一个具体的并发客户端中实现它(基于select函数),使得一旦服务器中的客户进程被终止的时候,客户端这 ...

  7. IO复用之select实现

    前言 在看过前文:初探IO复用后,想必你已对IO复用这个概念有了初步但清晰的认识.接下来,我要在一个具体的并发客户端中实现它( 基于select函数 ),使得一旦服务器中的客户进程被终止的时候,客户端 ...

  8. 多路IO复用模型--select, poll, epoll

    select 1.select能监听的文件描述符个数受限于FD_SETSIZE,一般为1024,单纯改变进程打开的文件描述符个数并不能改变select监听文件个数 2.解决1024以下客户端时使用se ...

  9. IO复用(Reactor模式和Preactor模式)——用epoll来提高服务器并发能力

    上篇线程/进程并发服务器中提到,提高服务器性能在IO层需要关注两个地方,一个是文件描述符处理,一个是线程调度. IO复用是什么?IO即Input/Output,在网络编程中,文件描述符就是一种IO操作 ...

随机推荐

  1. leetcode实战

    leetcode记录 两数之和 题目 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案. ...

  2. Docker Swarm Mode 学习笔记(聊聊 replicas)

    在 Swarm 集群中, 创建服务时可以通过设置 --replicas 参数来指定此服务在工作节点上运行的任务数. 示例 这里我们来创建一个 nginx 服务作为示例: version: '3' se ...

  3. Ubuntu如何启用root用户登录

    默认安装Ubuntu都是不允许以root用户进行登录的,想要以root用户进行登录需要进行一些操作,主要是以下几个步骤: 第一步 在终端输入命令:sudo passwd root 以普通用户登录系统, ...

  4. 微信小程序----wxss设置样式

    一.wxml 界面结构wxmL比较容易理解,主要是由八大类基础组件构成: 一.视图容器(View Container): 二.基础内容(Basic Content) 组件名 说明 组件名 说明 vie ...

  5. win10家庭版安装Docker for Windows

    0. 背景 硬件:小米笔记本 Air 13/Inter Core i7-7500U 操作系统:Windows 10 家庭中文版 补丁:截止2019/1/25最新稳定补丁 Docker:Docker W ...

  6. 13_文件系统访问列表_case语句及脚本选项

    FACL:Filesystem Access Control List利用文件扩展保存额外的访问控制权限 setfacl: -m:设定 u:UID:perm g:GID:perm root@kali: ...

  7. ios和android 浏览器适配问题总结

    转自 https://blog.csdn.net/wcy7916/article/details/83345705

  8. POJ 3616 奶牛挤奶

    Milking Time 贝茜是一个勤劳的牛.事实上,她如此​​专注于最大化她的生产力,于是她决定安排下一个N(1≤N≤1,000,000)小时(方便地标记为0..N-1),以便她生产尽可能多的牛奶. ...

  9. Linux服务器,服务管理--systemctl命令详解,设置开机自启动

    Linux服务器,服务管理--systemctl命令详解,设置开机自启动 syetemclt就是service和chkconfig这两个命令的整合,在CentOS 7就开始被使用了. 摘要: syst ...

  10. HTML CSS 特殊字符表

    HTML有许多特殊的字符,您对此有多少了解?平时在WEB制作中,您又有用到多少?或者说你在平时使用之时,是否也会碰到,有许多特殊字符要如何打印出来?比如说“笑脸”,比如说“版权号”.要是你用时忘记了这 ...