IO多路复用
IO多路复用---
①select:
1. 创建文件描述符集合 fd_set
2. 添加文件描述符到集合中 void FD_SET(int fd, fd_set *set);
3. 通知内核开始监测 select
4. 根据返回的结果做对应的操作(对io读、写操作)
int select(int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *exceptfds,
struct timeval *timeout);
功能:监测多路IO
参数:
nfds : 关注的文件描述符中的最大值+1
readfds:关注的读事件的文件描述符集
writefds:关注的写事件的文件描述符集合exceptfds:其他 异常
timeout : 超时时间,如果不设置:NULL
返回值:
成功:返回到达事件的个数
失败:-1
设置了超时时间:超时时间到达但没有事件,返回0
void FD_CLR(int fd, fd_set *set);
int FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);
读操作
#include "head.h"int main(int argc, const char *argv[])
{int maxfd = 0;char buff[1024] = {0};mkfifo("./myfifo", 0664);int fifofd = open("./myfifo", O_RDONLY);if (-1 == fifofd){perror("fail open fifo");return -1;}//创建文件描述符集合fd_set rdfds;fd_set tmpfds;//清空集合FD_ZERO(&rdfds);//添加关注的文件描述符到集合中FD_SET(0, &rdfds);maxfd = 0 > maxfd ? 0 : maxfd;FD_SET(fifofd, &rdfds);maxfd = fifofd > maxfd ? fifofd : maxfd;while (1){tmpfds = rdfds;//开始监测集合中的ioint cnt = select(maxfd+1, &tmpfds, NULL, NULL, NULL);if (cnt < 0){perror("fail select");return -1;}//根据返回的结果区分处理不同的ioif (FD_ISSET(0,&tmpfds)){memset(buff, 0, sizeof(buff));fgets(buff, sizeof(buff), stdin);printf("STDIN : %s\n", buff);}if (FD_ISSET(fifofd, &tmpfds)){memset(buff, 0, sizeof(buff));read(fifofd, buff, sizeof(buff));printf("FIFO : %s\n", buff);}}close(fifofd);return 0;
}
写操作
#include "head.h"int main(int argc, const char *argv[])
{ mkfifo("./myfifo", 0664);int fd = open("./myfifo", O_WRONLY);if (-1 == fd){perror("fail open fifo");return -1;}while (1){write(fd, "hello world", 11);sleep(1);}close(fd);return 0;
}
服务器
#include "head.h"int init_tcp_ser(const char *ip ,unsigned short port)
{ int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (-1 == sockfd){perror("fail socket");return -1;}struct sockaddr_in ser;ser.sin_family = AF_INET;ser.sin_port = htons(port);ser.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&ser, sizeof(ser));if (-1 == ret){perror("fail bind");return -1;}ret = listen(sockfd, 128);if (-1 == ret){perror("fail listen");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{pid_t pid = 0;int connfd = 0;pthread_t tid;int maxfd = 0;char buff[1024] = {0};int sockfd = init_tcp_ser("192.168.175.128", 50000);if (-1 == sockfd){return -1;}fd_set rdfds;fd_set tmpfds;FD_ZERO(&rdfds);FD_SET(sockfd, &rdfds);maxfd = sockfd > maxfd ? sockfd : maxfd;while (1){tmpfds = rdfds;int cnt = select(maxfd+1, &tmpfds, NULL, NULL, NULL);if (cnt < 0){perror("fail select");return -1;}if (FD_ISSET(sockfd, &tmpfds)){int connfd = accept(sockfd, NULL, NULL);if (connfd < 0){perror("fail accept");continue;}FD_SET(connfd, &rdfds);maxfd = connfd > maxfd ? connfd : maxfd;}for (int i = sockfd+1; i < maxfd; i++){if (FD_ISSET(i, &tmpfds)){memset(buff, 0, sizeof(buff));ssize_t size = recv(i, buff, sizeof(buff), 0);if (size < 0){perror("fail recv");FD_CLR(i, &rdfds);close(i);continue;}else if (0 == size){FD_CLR(i, &rdfds);close(i);continue; }printf("cli---> %s\n", buff);strcat(buff, "------ok!");size = send(i, buff, strlen(buff), 0);if (size < 0){perror("fail recv");FD_CLR(i, &rdfds);close(i);continue; }}}}return 0;
}
②epoll
1. 创建文件描述符集合 int epoll_create(int size);
2. 添加文件描述符到集合中 epoll_ctl()
3. 通知内核开始监测 epoll_wait()
4. 根据返回的结果做对应的操作(对io读、写操作)
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
功能:
参数:
epfd:文件描述符集合句柄
op:
EPOLL_CTL_ADD: 向集合中添加文件描述符
EPOLL_CTL_MOD: 修改集合
EPOLL_CTL_DEL :删除文件描述符
fd :操作的文件描述符
event :文件描述符所对应的事件
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 */
};
event : EPOLLIN : 读操作
EPOLLOUT : 写事件
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
功能:监测IO事件
参数:
epfd : 文件描述符集合句柄
events : 保存到达事件的结合的首地址
maxevents : 监测时事件的个数
timeout:超时时间
-1 :不设置超时时间
返回值:
成功:返回到达事件的个数
失败:-1
设置超时:超时时间到达返回0
读操作
#include "head.h"int epoll_add_fd(int epfds, int fd, uint32_t event)
{struct epoll_event ev;ev.events = event;ev.data.fd = fd;int ret = epoll_ctl(epfds, EPOLL_CTL_ADD, fd, &ev);if (-1 == ret){perror("fail epoll_ctl add");return -1;}return 0;
}int epoll_del_fd(int epfds, int fd)
{int ret = epoll_ctl(epfds, EPOLL_CTL_DEL, fd, NULL);if (-1 == ret){perror("fail epoll_ctl del");return -1;}return 0;
}int main(int argc, const char *argv[])
{int maxfd = 0;char buff[1024] = {0};mkfifo("./myfifo", 0664);int fifofd = open("./myfifo", O_RDONLY);if (-1 == fifofd){perror("fail open fifo");return -1;}struct epoll_event evs[2];int epfds = epoll_create(2);if (-1 == epfds){perror("fail epoll_create");return -1;}epoll_add_fd(epfds, 0, EPOLLIN);epoll_add_fd(epfds, fifofd, EPOLLIN);while (1){int cnt = epoll_wait(epfds, evs, 2, -1);if (cnt < 0){perror("fail epoll_wait");return -1;}for (int i = 0; i < cnt; i++){if (0 == evs[i].data.fd){memset(buff, 0, sizeof(buff));fgets(buff, sizeof(buff), stdin);printf("STDIN: %s\n", buff);}else if (fifofd == evs[i].data.fd){memset(buff, 0, sizeof(buff));ssize_t size = read(evs[i].data.fd, buff, sizeof(buff));if (size <= 0){epoll_del_fd(epfds, evs[i].data.fd);close(evs[i].data.fd);continue;}printf("FIFO: %s\n", buff);}}}return 0;
}
写操作
#include "head.h"int main(int argc, const char *argv[])
{ mkfifo("./myfifo", 0664);int fd = open("./myfifo", O_WRONLY);if (-1 == fd){perror("fail open fifo");return -1;}while (1){write(fd, "hello world", 11);sleep(1);}close(fd);return 0;
}