多路复用select

多路复用I/O:一个执行体监视多个文件描述符对象的状态是否改变,一旦改变通知其他执行体来实现。

基本思想:

1、 先构造一张有关描述符的表,然后调用一个函数,当这些文件描述符中的一个或者多个已准备好进行I/O时函数才返回

2、 函数返回时告诉进程那个描述符已准备就绪,可以进行I/O操作。

Select(int n,fd_set *read_fds,fd_set *write_fds,fd_set *except_fds,struct timeval *timeout);

注意两点:

1、 select函数返回之前会将集合中状态未改变的fd清除

2、 返回值为状态改变的文件描述符对象的个数。

3、 Select阻塞时内部会产生一个线程盯着描述符对象的状态改变。

参数:n:maxfd,所有监控的文件描述符中值最大的加1;

Read_fds:是否可读的文件描述符集

Write_fds:是否可写的文件描述符集

Except_fds:出错的文件描述符集

Timeout:如果设置为NULL,则会一直阻塞,直到文件描述符的状态改变

Struct timeval

{

Long tv_sec;

Long tv_usec;

} ;

文件描述符的几个宏:

FD_ZERO(fd_set *fdset):清空文件描述符集

FD_SET(int fd,fd_set *fdset):将fd加入到fd_set集中

FD_ISSET(int fd,fd_set*fdset):判断fd是否在fdset中

FD_CLR(fd,fd_set *fdset);将fd从fdset集中清除

Select函数使用范例(功能:本例使用的是tcp,select监听标准输入是否准备好字符串可读然后发送和socketfd是否可读,然后接受,实现以简单的qq通信)

客户端:
#include<stdio.h>
#include<pthread.h>
#include<netinet/in.h>
#include<stdlib.h>
#include<string.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
int main()
{
    int socketfd,ret;
    fd_set fd;
    FD_ZERO(&fd);
    FD_SET(0,&fd);

    socketfd = socket(PF_INET,SOCK_STREAM,0);
    FD_SET(socketfd,&fd);
    ret = select(socketfd+1,&fd,NULL,NULL,NULL);
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = PF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("192.168.1.46");

    if(connect(socketfd,(struct sockaddr *)&saddr,sizeof(struct sockaddr))<0)

        perror("connect() error!\n");
    char buf[20],buf1[20];
    while(1)
    {
        bzero(buf,20);
        bzero(buf1,20);

    FD_SET(0,&fd);
    FD_SET(socketfd,&fd);
    ret = select(socketfd+1,&fd,NULL,NULL,NULL);
            if(FD_ISSET(socketfd,&fd))
            {
            if(recv(socketfd,buf1,sizeof(buf1),0)<0)
                perror("recv() error!\n");
                printf("%s",buf1);
                continue;
            }
            if(FD_ISSET(0,&fd))
            {
//            printf("please input:\n");
            fgets(buf,20,stdin);
            if(send(socketfd,buf,strlen(buf),0)<0)
            perror("send() error!\n");
            continue;
            }    

        }
}
服务器端:
#include<stdio.h>
#include<netinet/in.h>
#include<stdlib.h>
#include<string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<pthread.h>
#include<strings.h>
int main()
{
    int fds[12];
    int maxfd = -1;
    int socketfd = socket(PF_INET,SOCK_STREAM,0);
    if(socketfd<maxfd)
        maxfd = socketfd;
    struct sockaddr_in saddr;
    memset(&saddr,0,sizeof(saddr));
    saddr.sin_family = PF_INET;
    saddr.sin_port = htons(6000);
    saddr.sin_addr.s_addr = inet_addr("192.168.193.2");
    int newsocketfd;
    int n = 1;
    setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(int));
    if(bind(socketfd,(struct sockaddr*)&saddr,sizeof(struct sockaddr_in))<0)
        perror("bind() error!\n");

    if(listen(socketfd,5)<0)
        perror("listen() error!\n");
    struct sockaddr_in caddr;
    int s = sizeof(struct sockaddr);
    newsocketfd=accept(socketfd,(struct sockaddr*)&caddr,&s);
    fd_set fd;
    FD_ZERO(&fd);
    int ret;
    char buf[20],buf1[20];
    int i;
    int rsize;
            printf("hello\n");
    while(1)
    {
        bzero(buf,20);
        bzero(buf1,20);
//            printf("hello\n");
        FD_SET(0,&fd);
//            printf("hello\n");
        FD_SET(newsocketfd,&fd);
//            printf("hello\n");
    select(newsocketfd+1,&fd,NULL,NULL,NULL);
        if(FD_ISSET(newsocketfd,&fd))
            {
//            printf("hello\n");
            if(recv(newsocketfd,buf1,sizeof(buf1),0)<0)
            perror("recv() error!\n");
            printf("%s",buf1);
//            printf("hello\n");
            continue;
            }

            if(FD_ISSET(0,&fd))
            {
            fgets(buf,20,stdin);
            if(send(newsocketfd,buf,strlen(buf),0)<0)
            perror("send() error!\n");
            continue;
            }
    }
    close(socketfd);
    close(newsocketfd);

}
时间: 2024-10-02 06:43:44

多路复用select的相关文章

I/O多路复用 SELECT POLL -- 内核实现

等待队列 先补充个基础知识――等待队列 认识 定义 wait_queue_head_t wait_queue; 初始化 init_waitqueue_head(&wait_queue); 等待 wait_event(queue, condition)   等待某个条件而进入睡眠 wait_event_interruptible(queue, condition)  等待某个条件而进入睡眠并允许信号中断睡眠 wait_event_timeout(queue, condition,timeout)

I/O多路复用select/poll/epoll

前言 早期操作系统通常将进程中可创建的线程数限制在一个较低的阈值,大约几百个.因此, 操作系统会提供一些高效的方法来实现多路IO,例如Unix的select和poll.现代操作系统中,线程数已经得到了极大的提升,如NPTL线程软件包可支持数十万的线程. I/O多路复用 select select 允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或指定时间后返回它. select函数原型 #include <sys/select.h> #include <sys/t

非阻塞io模型和io多路复用----select

一.四种io阻塞1.io阻塞:(1 等待数据处于阻塞状态(2从内核copy到用户态处于阻塞状态2.非io阻塞只有从内核copy到用户态处于阻塞状态3.io多路复用----->优势:可以同时监听多个对象(1从check----->ready 通过selec函数来做,处于阻塞状态(2从内核copy到用户态处于阻塞状态3.异步io不用阻塞二.io多路复用select  poll epoll 都属于io同步里面的io多路复用select:轮询问题,监听数量有限poll:提高了监听数量epoll:解决了

IO多路复用——select

IO多路复用 是同步IO的一种,用一个进程一次等待多个IO就绪事件的发生,加大概率,尽可能高效的等. 适用场景 (1)当客户处理多个描述字时(一般是交互式输入和网络套接口),必须使用I/O复用. (2)当一个客户同时处理多个套接口时,而这种情况是可能的,但很少出现. (3)如果一个TCP服务器既要处理监听套接口,又要处理已连接套接口,一般也要用到I/O复用. (4)如果一个服务器即要处理TCP,又要处理UDP,一般要使用I/O复用. (5)如果一个服务器要处理多个服务或多个协议,一般要使用I/O

python IO 多路复用 select poll epoll

三个多路复用模型的概念 select select 原理 select 是通过系统调用来监视着一个由多个文件描述符(file descriptor)组成的数组,当select()返回后,数组中就绪的文件描述符会被内核修改标记位(其实就是一个整数),使得进程可以获得这些文件描述符从而进行后续的读写操作.select饰通过遍历来监视整个数组的,而且每次遍历都是线性的. select 优点 select目前几乎在所有的平台上支持,良好跨平台性. select 缺点 每次调用select,都需要把fd集

IO多路复用-select

首先列一下,sellect.poll.epoll三者的区别 select select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作. select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一. select的一个缺点在于单个进程能够监视的文件描述符的数量存在

转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】

下面这篇,原理理解了, 再结合 这一周来的心得体会,整个框架就差不多了... http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的.下面记录下分别基于Select/Poll/Epoll的echo server实现.Python Select Server,可监控事件数量有限制: 1 2 3 4 5 6 7 8 9 10 11 12 13 14

I/O多路复用——select

系统提供select函数来实现多路复用I/O模型,select系统调用是用来让我们的程序监视多个文件句柄的状态变化的.程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了状态改变. select API: 1)nfds参数指定被监听的文件描述符的总数.它通常被设置为select监听的所有文件描述符中的最大值加1,因为文件描述符是从0开始计数的. 2)readfds.writefds和exceptfds参数都是输入输出型参数,分别指向可读.可写和异常等事件对应的文件描述符集合.作

多路复用select和epoll的区别(转)

先说下本文框架,先是问题引出,然后概括两个机制的区别和联系,最后介绍每个接口的用法 一.问题引出 联系区别 问题的引出,当需要读两个以上的I/O的时候,如果使用阻塞式的I/O,那么可能长时间的阻塞在一个描述符上面,另外的描述符虽然有数据但是不能读出来,这样实时性不能满足要求,大概的解决方案有以下几种: 1.使用多进程或者多线程,但是这种方法会造成程序的复杂,而且对与进程与线程的创建维护也需要很多的开销.(Apache服务器是用的子进程的方式,优点可以隔离用户) 2.用一个进程,但是使用非阻塞的I