多路I/O复用的三种实现方式
select
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
int main(){
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd == -1){
perror("socket");
exit(-1);
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9999);
saddr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(lfd, (struct sockaddr*) &saddr, sizeof(saddr));
if(ret == -1){
perror("bind");
exit(-1);
}
ret = listen(lfd, 8);
if(ret == -1){
perror("listen");
exit(-1);
}
fd_set rdset, temp;
FD_ZERO(&rdset);
FD_SET(lfd, &rdset);
int maxfd = lfd;
while(1){
temp = rdset;
ret = select(maxfd + 1, &temp, NULL, NULL, NULL);
if(ret == -1){
perror("select");
exit(-1);
}
else if(ret == 0){
continue;
}
else if(ret > 0){
if(FD_ISSET(lfd, &temp)){
struct sockaddr_in cliaddr;
int len = sizeof(cliaddr);
int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);
if(cfd == -1){
perror("accept");
exit(-1);
}
FD_SET(cfd, &rdset);
maxfd = maxfd > cfd ? maxfd : cfd;
}
for(int i = lfd + 1; i <= maxfd; i++){
if(FD_ISSET(i, &temp)){
char recv[1024] = {0};
int size = read(i, recv, sizeof(recv));
if(size == -1){
perror("read");
exit(-1);
}
if(size == 0){
printf("client close...\n");
close(i);
FD_CLR(i, &rdset);
}
if(size > 0){
printf("recv : %s\n", recv);
write(i, recv, strlen(recv) + 1);
}
}
}
}
}
close(lfd);
return 0;
}
poll
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <poll.h>
int main(){
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd == -1){
perror("socket");
exit(-1);
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9999);
saddr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(lfd, (struct sockaddr*)&saddr, sizeof(saddr));
if(ret == -1){
perror("bind");
exit(-1);
}
ret = listen(lfd, 128);
if(ret == -1){
perror("listen");
exit(-1);
}
struct pollfd fds[1024];
for(int i = 0; i < 1024; i++){
fds[i].fd = -1;
fds[i].events = POLLIN;
}
fds[0].fd = lfd;
int nfds = 0;
while(1){
ret = poll(fds, nfds + 1, -1);
if(ret == -1){
perror("poll");
exit(-1);
}
else if(ret == 0){
continue;
}
else if(ret > 0){
if(fds[0].revents & POLLIN){
struct sockaddr_in cliaddr;
int len = sizeof(cliaddr);
int cfd = accept(lfd, (struct sockaddr*)&cliaddr, &len);
for(int i = 1; i < 1024; i++){
if(fds[i].fd == -1){
fds[i].fd = cfd;
fds[i].events = POLLIN;
break;
}
}
nfds = nfds > cfd ? nfds : cfd;
}
for(int i = 1; i <= nfds; i++){
if(fds[i].revents & POLLIN){
char recv[1024];
int size = read(fds[i].fd, recv, sizeof(recv));
if(size == -1){
perror("read");
exit(-1);
}
else if(size == 0){
printf("client close....\n");
close(fds[i].fd);
fds[i].fd = -1;
}
else if(size > 0){
printf("recv : %s\n", recv);
write(fds[i].fd, recv, strlen(recv) + 1);
}
}
}
}
}
close(lfd);
return 0;
}
epoll
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
int main(){
int lfd = socket(AF_INET, SOCK_STREAM, 0);
if(lfd == -1){
perror("socket");
exit(-1);
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(9999);
saddr.sin_addr.s_addr = INADDR_ANY;
int ret = bind(lfd, (struct sockaddr*) &saddr, sizeof(saddr));
if(ret == -1){
perror("bind");
exit(-1);
}
ret = listen(lfd, 8);
if(ret == -1){
perror("listen");
exit(-1);
}
int epfd = epoll_create(100);
struct epoll_event epev;
epev.events = EPOLLIN;
epev.data.fd = lfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &epev);
struct epoll_event epevs[1024];
while(1){
ret = epoll_wait(epfd, epevs, 1024, -1);
if(ret == -1) {
perror("epoll_wait");
exit(-1);
}
printf("ret = %d\n", ret);
for(int i = 0; i < ret; i++) {
int curfd = epevs[i].data.fd;
if(curfd == lfd) {
// 监听的文件描述符有数据达到,有客户端连接
struct sockaddr_in cliaddr;
int len = sizeof(cliaddr);
int cfd = accept(lfd, (struct sockaddr *)&cliaddr, &len);
epev.events = EPOLLIN;
epev.data.fd = cfd;
epoll_ctl(epfd, EPOLL_CTL_ADD, cfd, &epev);
} else {
if(epevs[i].events & EPOLLOUT) {
continue;
}
// 有数据到达,需要通信
char buf[1024] = {0};
int len = read(curfd, buf, sizeof(buf));
if(len == -1) {
perror("read");
exit(-1);
} else if(len == 0) {
printf("client closed...\n");
epoll_ctl(epfd, EPOLL_CTL_DEL, curfd, NULL);
close(curfd);
} else if(len > 0) {
printf("read buf = %s\n", buf);
write(curfd, buf, strlen(buf) + 1);
}
}
}
}
close(lfd);
close(epfd);
return 0;
}