Linux Select

在Linux中,我们可以使用select函数实现I/O端口的复用,传递给 select函数的参数会告诉内核:

•我们所关心的文件描述符
      •对每个描述符,我们所关心的状态。(我们是要想从一个文件描述符中读或者写,还是关注一个描述符中是否出现异常)
      •我们要等待多长时间。(我们可以等待无限长的时间,等待固定的一段时间,或者根本就不等待)
   从 select函数返回后,内核告诉我们一下信息:
      •对我们的要求已经做好准备的描述符的个数
      •对于三种条件哪些描述符已经做好准备.(读,写,异常)

select
——用于IO多路复用
(1)函数原型

#include<sys/time.h>
#include<sys/types.h>
#include<unistd.h>
int select(int n,fd_set * readfds,fd_set * writefds,fd_set * exceptfds,struct timeval * timeout);

(2)参数
        n:最大的文件描述词加1;
        readfds、writefds 和exceptfds:称为描述词组,是用来回传该描述词的读,写或例外的状况;
        timeout:用来设置select()的等待时间。

struct timeval
{time_t tv_sec;time_t tv_usec;
};

(3)返回值
        如果参数timeout设为NULL则表示select()没有timeout。
执行成功则返回文件描述词状态已改变的个数,如果返回0代表在描述词状态改变前已超过timeout时间,当有错误发生时则返回-1,错误原因存于errno,此时参数readfds,writefds,exceptfds和timeout的值变成不可预测。
EBADF 文件描述词为无效的或该文件已关闭
EINTR 此调用被信号所中断
EINVAL 参数n 为负值。

ENOMEM 核心内存不足

常见的程序片段:fs_set readset;
FD_ZERO(&readset);
FD_SET(fd,&readset);
select(fd+1,&readset,NULL,NULL,NULL);
if(FD_ISSET(fd,readset){……}
#ifndef _SELECT_H_
#define _SELECT_H_#include "wrap.h"
#include "client_list.h"
#include "server_queue.h"#define SERVER_PORT     6780
#define MAXLINE         100
#define OPEN_MAX        65535
#define TCP_FRAME_SIZE  1200typedef struct
{int sockfd;  // server socketint port;    // server portstruct sockaddr_in addr; // server addrint maxi;  // select maxint maxfd;int aggregate[FD_SETSIZE];// select aggregationfd_set allset;server_queue_t send_queue; // server send data queue to clientserver_queue_t recv_queue; // server recv data queue from clientpthread_t send_thread;pthread_t recv_thread;client_t *client;  // client list -- save all client info
} server_t;/* recv and send queue frame */
typedef struct
{int sockfd;  // client socketuint16_t length;char data[TCP_FRAME_SIZE];
} __packed tcp_frame_t;//==========================================================
server_t *SocketInit(void);#endif /* _SELECT_H_ */
#include "select.h"
#include "debug.h"static server_t *socket_init(void)
{int opt = 1, i;server_t *current;current = (server_t *)malloc(sizeof(server_t));current->port = SERVER_PORT;current->sockfd = Socket(AF_INET, SOCK_STREAM, 0);// SOL_SOCKET: port can same, ip notSetsockopt(current->sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));current->addr.sin_family = AF_INET;current->addr.sin_port = htons(current->port);current->addr.sin_addr.s_addr = INADDR_ANY;Bind(current->sockfd, (struct sockaddr *)&current->addr, sizeof(current->addr));Listen(current->sockfd, MAXLINE);current->maxi = -1;current->maxfd = current->sockfd;for(i = 0; i < FD_SETSIZE; ++i){current->aggregate[i] = -1;}FD_ZERO(current->allset);FD_SET(current->sockfd , current->allset);ServerQueueInit(&current->send_queue, TCP_FRAME_SIZE);ServerQueueInit(&current->recv_queue, TCP_FRAME_SIZE);return current;
}static void socket_accept(server_t *arg, fd_set *rset)
{server_t *current = arg;struct sockaddr_in addr;int len = sizeof(struct sockaddr_in), i;int new_fd = Accept(current->sockfd, (struct sockaddr *)&addr, &len);debug("new connection client_fd ( %d ) %s: %d\n", new_fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));for(i = 0; i < FD_SETSIZE; ++i){if(current->aggregate[i] < 0){// add new_fd to aggregatecurrent->aggregate[i] = new_fd;break;}}if(FD_SETSIZE == i){printf("too many connects\n");Close(new_fd);return;}FD_SET(new_fd , current->allset);if(new_fd > current->maxfd){current->maxfd = new_fd;}if(i > current->maxi){current->maxi = i;}/* add client node */client_t *node = (client_t *)malloc(sizeof(client_t));node->sockfd = new_fd;memcpy(&node->addr, &addr, sizeof(struct sockaddr_in));ClientAdd(node);
}static void socket_recv(server_t *arg, fd_set *rset, int ret)
{server_t *current = arg;int i, sockfd, length = 0;tcp_frame_t write;for(i = 0; i <= current->maxi; ++i){if((sockfd = current->aggregate[i]) < 0){continue;}if(FD_ISSET(sockfd , rset)){length = recv(sockfd, write.data, TCP_FRAME_SIZE, 0);if(0 == length){/* delete client node, close connect socket */debug("client[%d] close\n", sockfd);ClientDel(sockfd);Close(sockfd);FD_CLR(sockfd , current->allset);current->aggregate[i] = -1;continue;}else if(length > 0){write.sockfd = sockfd;write.length = length;server_debug(write.data, write.length);// add data to recv_queue, pop in other,if(ServerQueueWrite(&current->recv_queue, (uint8_t *)&write, sizeof(tcp_frame_t)) == 0){debug("push failure...queue full...\n");}}if(--ret <= 0){break;}}}
}static void *server_recv_thread(void *arg)
{server_t *current = (server_t *)arg;fd_set rset;struct timeval timeout;while(1){rset = current->allset;timeout.tv_sec = 0;timeout.tv_usec = 200;int ret = Select(current->maxfd + 1 , &rset, NULL , NULL , &timeout);if(0 == ret){continue;}if(FD_ISSET(current->sockfd, &rset)){socket_accept(current, &rset); // a new connect come}if(--ret < 0){continue;}socket_recv(current, &rset, ret); // a exsit connect send data to us}Close(current->sockfd);return NULL;
}static void *server_send_thread(void *arg)
{server_t *current = (server_t *)arg;tcp_frame_t *read = NULL;while(1){//read = (tcp_frame_t*)ServerQueueRead(&current->send_queue, sizeof(tcp_frame_t));if(read != NULL){//server_debug(read->data, read->length);}usleep(100);}return NULL;
}server_t * SocketInit(void)
{server_t *current = socket_init();debug("create thread...\r\n");pthread_create(&current->send_thread, NULL, server_send_thread, current);pthread_create(&current->recv_thread, NULL, server_recv_thread, current);return current;
}

Linux Select相关推荐

  1. linux—select具体解释

    linux-select具体解释 select系统调用时用来让我们的程序监视多个文件句柄的状态变化的.程序会停在select这里等待,直到被监视的文件句柄有一个或多个发生了状态改变. 关于文件句柄,事 ...

  2. Linux select函数用法和原理

    select函数的用法和原理 Linux上的select函数 select函数用于检测一组socket中是否有事件就绪.这里的事件为以下三类: 读事件就绪 在socket内核中,接收缓冲区中的字节数大 ...

  3. linux select系统调用函数分析,Linux select系统调用

    linux系统提供了系统调用select,它允许程序挂起,并等待从不止一个文件描述符的输入.原理很简单: 1. 获取所需要的文件描述符列表: 2. 将此列表传给select: 3. select挂起直 ...

  4. linux select使用

    select系统调用是用来让我们的程序监视多个文件句柄(file descriptor)的状态变化的.程序会停在select这里等待,直到被监视的文件句柄有某一个或多个发生了状态改变. 文 件在句柄在 ...

  5. OS / Linux / Select 调用流程

    Linux下select调用的过程: 1.用户层应用程序调用 select(),底层调用 poll() . 2.核心层调用 sys_select() ------> do_select() . ...

  6. linux select read阻塞_linux下的IO模型详解

    开门见山,Linux下的如中IO模型:阻塞IO模型,非阻塞IO模型,IO复用模型,信号驱动IO模型,异步IO模型,见下图 接下来一一讲解这5种模型 阻塞型IO:最简单的一种IO模型,简单理解就是死等, ...

  7. Linux select TCP并发服务器与客户端编程

    介绍:运行在ubuntu linux系统,需要先打开一个终端运行服务端代码,这时,可以打开多个终端同时运行多个客户端代码(注意客户端数目要小于MAX_FD);在客户端输入数据后回车,可以看见服务器收到 ...

  8. linux select shell,linux之shell编程select和case用法

    shell里的select用法: 语法:#i/bin/bash select 变量 in 列表 do 要执行的语句 done 举例: #!/bin/bash echo "What is yo ...

  9. Linux select/poll机制原理分析

    转载一篇文章,讲解select和poll机制的,分享给大家. 前言 Read the fucking source code!  --By 鲁迅 A picture is worth a thousa ...

最新文章

  1. 2021-2027年中国室内定位市场研究及前瞻分析报告
  2. java上传文件文件保存后损坏_Laravel存储文件在上传时会损坏
  3. android studio创建构造方法,使用Android studio创建你的第一个项目
  4. 数据分析之 pandas
  5. opencv外接矩形矫正
  6. 金蝶K3销售价格控制模块探讨
  7. 『天涯杂谈』语不惊人死不休——2004年最一针见血的500句话(前100句)
  8. Python E化-爬虫VOA-下载MP3
  9. 笔记本打印时出现打印机出现异常配置问题_win10系统打印机出现administrator无法打印如何解决...
  10. Whois 信息与个人隐私
  11. 基于STM32设计的健康检测设备(测温心率计步)
  12. 【JAVA|Swing】简单表格的制作
  13. oracle大数据量查询超时排查
  14. 【毕业设计】人脸识别门禁系统
  15. TRC丨艾美捷TRC ACP-5197说明书
  16. 【互联网的恩怨情仇】盘点2015年互联网十大撕逼事件
  17. Chocolatey 食用说明
  18. Odoo进销存(采购、销售、仓库)入门教程 - 上
  19. SQLSTATE[HY000]: General error: 1366 Incorrect string value: ‘\xF0\x9F\x90\xA3\xF0\x9F...‘ for colum
  20. 安全生产隐患排查治理信息化系统软件

热门文章

  1. Java对数组的操作(二)——集合与数组的切换
  2. D3D9 effect (hlsl)(转)
  3. Memcache应用场景
  4. 矩阵的变换。包括缩放、平移、错切
  5. 利用open***建立桥接***[zt]
  6. linux bash函数里面调用命令行,Linux-在gnome-terminal -x中运行bash函数
  7. 有字符csv文件导入matlab_Matlab:如何读取CSV文件以及如何读取带有字符串数据项的CSV文件...
  8. c语言 malloc_C语言快速入门——动态内存分配
  9. 如何理解操作系统的不确定性_温度最低-273度,最高却能有1.4亿亿亿亿度,如何定义的?...
  10. python中错误和异常处理