http server 值select 学习

select  函数

1、用途

    在编程的过程中,经常会遇到许多阻塞的函数,好像read和网络编程时使用的recv, recvfrom函数都是阻塞的函数,当函数不能成功执行的时候,程序就会一直阻塞在这里,无法执行下面的代码。这是就需要用到非阻塞的编程方式,使用select函数就可以实现非阻塞编程。

       select函数是一个轮循函数,循环询问文件节点,可设置超时时间,超时时间到了就跳过代码继续往下执行。

2、原理

       select需要驱动程序的支持,驱动程序实现fops内的poll函数。select通过每个设备文件对应的poll函数提供的信息判断当前是否有资源可用(如可读或写),如果有的话则返回可用资源的文件描述符个数,没有的话则睡眠,等待有资源变为可用时再被唤醒继续执行。

3、协议定义

int select(int nfds,  fd_set* readset,  fd_set* writeset,  fe_set* exceptset,  struct timeval* timeout);

参数:

       nfds           需要检查的文件描述字个数
       readset     用来检查可读性的一组文件描述字。
       writeset     用来检查可写性的一组文件描述字。
       exceptset  用来检查是否有异常条件出现的文件描述字。(注:错误不包括在异常条件之内)
       timeout      超时,填NULL为阻塞,填0为非阻塞,其他为一段超时时间

返回值:

       返回fd的总数,错误时返回SOCKET_ERROR

4、

void http_tick(void)
{
    int max_fd = -1;      // 最大socket 数目加1 用于 selsect 函数
    int cli_addr_len;     //客户端地址

    int sock_fd = -1;
    int new_conn_fd = -1;

    fd_set read_set;
    fd_set select_read_set;


    struct sockaddr_t serv_addr;
    struct sockaddr_t cli_addr;

    struct timeval_t t, timeout;
    timeout.tv_sec = 2;
    timeout.tv_usec = 0;

    t.tv_sec = 2;
    t.tv_usec = 0;

    FD_ZERO(&read_set);
    FD_ZERO(&select_read_set);
    for (uint8 i = 0; i < MAX_CLIENT; i++)
    {
        clientfd[i] = -1;
    }
    if (sock_fd==-1)
    {
        sock_fd = socket(AF_INET, SOCK_STREAM, 0);
        if (sock_fd < 0)
        {
            uart_Debug("Fail to socket");
        }

    }
    unsigned int value = 1;
    if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,  (void *)&value, sizeof(value)) < 0)
    {
        uart_Debug("Fail to setsockopt");
    }

    memset(&serv_addr, 0, sizeof(serv_addr));
    memset(&cli_addr, 0, sizeof(cli_addr));

    serv_addr.s_port = 80;
    if (bind(sock_fd, &serv_addr, sizeof(serv_addr))< 0)
    {
        uart_Debug("Fail to bind");

    }
    if (listen(sock_fd, 0) < 0)
    {
        uart_Debug("Fail to listen");

    }
    max_fd = sock_fd;
    FD_SET(sock_fd, &read_set);
    for(;;)
    {

        max_fd = sock_fd;
        for (uint8 i = 0; i < MAX_CLIENT; i++)
        {
            if (max_fd < clientfd[i])
            {
                max_fd = clientfd[i];
            }
        }

        select_read_set = read_set;
        uint8 ret = select(max_fd + 1, &select_read_set, NULL, NULL, &timeout);
        if (ret == 0)
        {
 //           uart_Debug("timeout\n");
        }
        else if (ret < 0)
        {
            uart_Debug("error occur\r\n");
        }
        else
        {
            if (FD_ISSET(sock_fd, &select_read_set))
            {
//                uart_Debug("new client comes\r\n");

                cli_addr_len = sizeof(cli_addr);
                new_conn_fd =accept(sock_fd, (struct sockaddr_t*)&cli_addr, &cli_addr_len);
                if (new_conn_fd < 0)
                {
                    uart_Debug("Fail to accept\r\n");
                }
                else
                {
                    for(uint8 i=0; i




你可能感兴趣的:(日常工作记录)