Linux 数据通信之IO复用模块
概念
- 单个句柄占用一个输入 输出 造成资源过剩,使用文件集合占用一个输入输出
方法
- select
- poll
- epoll
select IO 复用手段
- 对象–>fd_set 文件集合
- 使用领域
- IO复用流程
- struct fd_set
-
分配 struct fd_set rfds;
-
设置
初始化 FD_ZERO(&rfds);
加入句柄 FD_SET(fd, &rfds);
移除句柄 FD_CLR(int fd, fd_set *set); -
使用
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);int nfds 文件集合中最大的fd+1
struct timeval timeout
struct timeval {
long tv_sec; / seconds /
long tv_usec; / microseconds */
};判断由哪个fd引起的返回 int FD_ISSET(int fd, fd_set *set);
- 使用方法
首先进行select 等待
accept
- 注意: 每次重新发起select时,需要对fd_set重新添加
IO复用流程
select demo演示
/* According to POSIX.1-2001 */
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
使用场合
服务器:
tcp 与 udp同时进行监听
既作为服务器 又作为客户端 代理 select
客户端:
监听多个句柄时() 1000
stdin
fd 进程间通信句柄
socket
poll机制
- 分析和已有模型的区别
select —>fd_set包含需要进行IO复用的句柄
poll ---->pollfd包含需要进行IO复用的句柄 pollfd句柄链表 句柄链表的头 - 对象
struct pollfd{
int fd; //当前的处理句柄
short events; 句柄关心的事件
short revents;
}
event
/* These are specified by iBCS2 */
#define POLLIN 0x0001
#define POLLPRI 0x0002
#define POLLOUT 0x0004
#define POLLERR 0x0008
#define POLLHUP 0x0010
#define POLLNVAL 0x0020
listen_fd
pollfd
.fd = listen_fd
.events = POLLIN | POLLPRI
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
/* The rest seem to be more-or-less nonstandard. Check them! */
#define POLLRDNORM 0x0040
#define POLLRDBAND 0x0080
#ifndef POLLWRNORM
#define POLLWRNORM 0x0100
#endif
#ifndef POLLWRBAND
#define POLLWRBAND 0x0200
#endif
#ifndef POLLMSG
#define POLLMSG 0x0400
#endif
#ifndef POLLREMOVE
#define POLLREMOVE 0x1000
#endif
#ifndef POLLRDHUP
#define POLLRDHUP 0x2000
#endif
#define POLLFREE 0x4000 /* currently only for epoll */
#define POLL_BUSY_LOOP 0x8000
revents 回复事件
事件返回指针
struct pollfd;
pollfd.fd
pollfd.event
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
revents
struct pollfd{
int fd; //当前的处理句柄
short events; 句柄关心的事件
short revents;
}
fd_set pollfd
- 使用poll select 实现回射服务器(客户端发什么 服务端回什么)
要求:客户端和服务端都需要使用select的机制 - 设计一个tcp的代理
select 与 poll的内核机制分析
select poll
int 80 systemcall
__syscall_start
sys_select
core_sys_select
do_select
*timeout -= __timeout;
const struct file_operations *f_op;
unsigned int (*poll) (struct file *, struct poll_table_struct *);
f_op->poll —>mask
unsigned int datagram_poll(struct file *file, struct socket *sock,
poll_table *wait)
{
struct sock *sk = sock->sk;
unsigned int mask;
poll_wait(file, sk->sk_sleep, wait);
mask = 0;
/* exceptional events? */
if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
mask |= POLLERR;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLRDHUP;
if (sk->sk_shutdown == SHUTDOWN_MASK)
mask |= POLLHUP;
/* readable? */
if (!skb_queue_empty(&sk->sk_receive_queue) ||
(sk->sk_shutdown & RCV_SHUTDOWN))
mask |= POLLIN | POLLRDNORM;
/* Connection-based need to check for termination and startup */
if (connection_based(sk)) {
if (sk->sk_state == TCP_CLOSE)
mask |= POLLHUP;
/* connection hasn't started yet? */
if (sk->sk_state == TCP_SYN_SENT)
return mask;
}
/* writable? */
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
return mask;
}
epoll
- 并发性高,可同时监听C10K以上级别的客户事件
select ----> fd—>fd_set --轮训
poll ---- fd—>pollfd
epoll ----> fd—event
epoll : 大规模并发服务框架
epoll+threadpool+mysql - 对象
epoll_fd epoll_event
创建 epollfd对象:
int epoll_create(int size); 返回值 epoll_fd epoll_event
设置 epollfd对象:
创建 epoll_event对象
struct epoll_event ep_ev;
设置 epoll_event对象
ep_ev.events = EPOLLIN;//数据的读取
ep_ev.data.fd = listen_sock;
使用 epoll_event对象
epoll_ctl(int epfd,int op, int fd, struct epoll_event *event);
epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listen_sock,&ep_ev);
使用epollefd对象:
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
// 第二个struct epoll_event *events是用来做返回的
// maxevents
// timeout
typedef union epoll_data {
void *ptr;
int fd;
uint32_t u32;
uint64_t u64;
} epoll_data_t;
struct epoll_event {
uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
EPOLL_CTL_ADD
EPOLL_CTL_MOD
EPOLL_CTL_DEL