IO复用:Select

Select

接口

1.创建

int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

nfds:最大的文件描述符加1.
readfds: 用于检查可读的.
writefds:用于检查可写性.
exceptfds:用于检查异常的数据.
timeout:一个指向timeval结构的指针.用于决定select等待I/o的最长时间.如果为空将一直等待.

timeval结构体定义:
struct timeval{
long tv_sec; // seconds
long tv_usec; // microseconds
}

返回值:>0是已就绪的文件句柄的总数.=0为超时,<0表示出错.错误: errno .

2.设置
int FD_ZERO(fd_set *fdset); //一个 fd_set类型变量的所有位都设为0
int FD_CLR(int fd, fd_set *fdset); //清除某个位时可以使用
int FD_SET(int fd, fd_set *fd_set); //设置变量的某个位置位
int FD_ISSET(int fd, fd_set *fdset); //测试某个位是否被置位

fd_set.是一个数组的宏定义.实际上是一long类型的数组.每一个数组元素都能与一打开的文件句柄(socket.文件.管道.设备等)建立联系.建立联系的工作由程序员完成.当调用select()时.由内核根据IO状态修改fd_set的内容.由此来通知执行了select()的进程哪个句柄可读.

Select_deom

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>

int main()
{
    
    
    int server_sockfd, client_sockfd;
    int server_len, client_len;
    struct sockaddr_in server_address;
    struct sockaddr_in client_address;
    int result;
    fd_set readfds, testfds; //创建select数组
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);//建立服务器端socket
    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = htonl(INADDR_ANY);
    server_address.sin_port = htons(9000);
    server_len = sizeof(server_address);
    bind(server_sockfd, (struct sockaddr*)&server_address, server_len);
    listen(server_sockfd, 5); //监听队列最多容纳5个
    FD_ZERO(&readfds);
    FD_SET(server_sockfd, &readfds);//将服务器端socket加入到集合中
    while (1)
    {
    
    
        char ch;
        int fd;
        int nread;
        testfds = readfds;//将需要监视的描述符集copy到select查询队列中,select会对其修改,所以一定要分开使用变量
        printf("server waiting\n");

        /*无限期阻塞,并测试文件描述符变动 */
        result = select(FD_SETSIZE, &testfds, (fd_set*)0, (fd_set*)0, (struct timeval*)0); //FD_SETSIZE:系统默认的最大文件描述符
        if (result < 1)
        {
    
    
            perror("server5");
            exit(1);
        }

        /*扫描所有的文件描述符*/
        for (fd = 0; fd < FD_SETSIZE; fd++)
        {
    
    
            /*找到相关文件描述符*/
            if (FD_ISSET(fd, &testfds))
            {
    
    
                /*判断是否为服务器套接字,是则表示为客户请求连接。*/
                if (fd == server_sockfd)
                {
    
    
                    client_len = sizeof(client_address);
                    client_sockfd = accept(server_sockfd,
                        (struct sockaddr*)&client_address, &client_len);
                    FD_SET(client_sockfd, &readfds);//将客户端socket加入到集合中
                    printf("adding client on fd %d\n", client_sockfd);
                }
                /*客户端socket中有数据请求时*/
                else
                {
    
    
                    ioctl(fd, FIONREAD, &nread);//取得数据量交给nread

                    /*客户数据请求完毕,关闭套接字,从集合中清除相应描述符 */
                    if (nread == 0)
                    {
    
    
                        close(fd);
                        FD_CLR(fd, &readfds); //去掉关闭的fd
                        printf("removing client on fd %d\n", fd);
                    }
                    /*处理客户数据请求*/
                    else
                    {
    
    
                        read(fd, &ch, 1);
                        sleep(5);
                        printf("serving client on fd %d\n", fd);
                        ch++;
                        write(fd, &ch, 1);//读取客户端一个字符后 进行++操作返回
                    }
                }
            }
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43507406/article/details/114763259