尝鲜select多路复用

尝鲜select多路复用

问题:

如何增强服务端能力,同时支持多个客户端?

Linux的设计哲学

一切皆文件

  • Linux中的文件是什么?
    • 狭义:
      • 文件系统中物理意义上的文件(逻辑上关联的数据集合)
    • 广义
      • 设备,管道,内存…
      • Linux管理的一切对象
  • 理解文件描述符(File Descriptor)
    • 文件描述符是一个非负整数值,本质上一个句柄
    • 一切对用户(程序员)透明的资源标识都可以看做句柄
    • 用户使用文件描述符(句柄)与内核交互
    • 内核通过文件描述符操作对应资源的数据结构
  • 一切皆文件的意义
    • 统一各种设备的操作方式(open,read,write,close)
    • 如:
      • IO设备(命令行,显示器)
      • 网络设备(网卡)

Linux文件操作编程模式

  • 编程实验——以文件类型操作命令行
#include <stdio.h>
#include <unistd.h>

int main(void)
{
    int iofd = 0;
    int len = 0;
    char str[] = "Titai,soft\n";

    write(iofd, str, sizeof(str));

    len = read(0, str, 5);

    str[len] = '\0';

    printf("%s\n",str);

    return 0;
}

事件相关函数的分类

  • 阻塞式函数
    • 函数调用后需要等待某个事件发生后才会返回
  • 非阻塞式函数
    • 函数调用后能够及时返回(仅标记等待的事件)
    • 事件发生后以回调方式传递
  • 阻塞vs轮询
    • 轮询指依序询问每一个相关设备是否需要服务的方式
    • 轮询可用于解决函数导致程序无法继续执行的问题

神奇的selec()函数

  • select()用于监视指定的文件描述符是否产生事件
  • 可通过轮询的方式检测目标事件(事件产生则标记发生变化)
  • 根据事件类型做出具体处理(如:读取数据)
int select(int maxfd,
          fd_set* readset,
          fd_set* writeset,
          fd_set* exceotset,
          const struct timeval* timeout);

select()函数的使用步骤

尝鲜select多路复用

select()相关数据类型及操作

fd0 fd1 fd2 fd3
0 1 1 0
FD_ZERO(fd_set* fdset);//将fd_set变量的所有位设置为0
FD_SET(int fd,fd_set* fdset);//在fd_set中指定需要监听的fd
FD_CLR(int fd, fd_set* fdset);//在fd_set中剔除fd,不再监听
FD_ISSET(int fd, fd_set* fdset);//在fd_set查看是否包含fd

代码示例

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>

int main(void)
{
    char s[] = "hello world\n";
    fd_set reads = {0};
    fd_set tmps = {0};
    int iofd = 0;
    struct timeval timeout = {0};
    int r = -1;
    int len = 0;

    FD_ZERO(&reads);
    FD_SET(iofd, &reads);

    while( 1 )
    {
        tmps = reads;

        timeout.tv_sec = 0;
        timeout.tv_usec = 10*1000;

        r = select(1, &tmps, 0, 0, &timeout);
        if(r > 0)
        {
            len = read(1, s, sizeof(s));
            s[len] = 0;
            printf("s[]:%s\n",s);
        }
        else if( r == 0)
        {
            //so something
            static int count = 0;
            usleep(10 * 1000);
            count++;

            if(count > 100)
            {
                printf("do something else\n");
                count = 0;
            }
        }
        else
        {
            break;
        }

    }
    return 0;
}
上一篇:GCD介绍(二): 多核心的性能


下一篇:第83期-基础技巧:双指针 有序数组的平方