#include <sys/wait.h>
#include <stdint.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <sys/times.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
/**
* https://man7.org/linux/man-pages/man7/epoll.7.html
The following system calls are provided to create and manage an
epoll instance:
• epoll_create(2) creates a new epoll instance and returns a file
descriptor referring to that instance. (The more recent
epoll_create1(2) extends the functionality of epoll_create(2).)
• Interest in particular file descriptors is then registered via
epoll_ctl(2), which adds items to the interest list of the
epoll instance.
• epoll_wait(2) waits for I/O events, blocking the calling thread
if no events are currently available. (This system call can be
thought of as fetching items from the ready list of the epoll
instance.)
*/
#define MAX_EVENTS 10
int setnonblocking(int fd) {
int flags;
if (-1 == (flags = fcntl(fd, F_GETFL, 0)))
flags = 0;
return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
void do_use_fd(int fd, char *buffer) {
printf("do_use_fd \n");
while (1) {
int length = read(fd, buffer, 1023);
if (length <= 0) {
printf("read error \n");
perror("read error");
break;
}
buffer[length] = '\0';
printf("%s", buffer);
write(fd, buffer, length);
}
}
int main() {
char buffer[1024] = { 0 };
int listenfd = 0;
int conn_sock = 0;
struct sockaddr_in address;
int addrlen = sizeof(address);
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&address, '0', addrlen);
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(INADDR_ANY);
address.sin_port = htons(8080);
bind(listenfd, (struct sockaddr*) &address, addrlen);
if (listen(listenfd, 3) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
int epollfd;
struct epoll_event ev;
struct epoll_event events[MAX_EVENTS];
int nfds;
epollfd = epoll_create1(0);
if (epollfd == -1) {
perror("epoll_create1");
exit(EXIT_FAILURE);
}
ev.events = EPOLLIN;
ev.data.fd = listenfd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) {
perror("epoll_ctl: listen_sock");
exit(EXIT_FAILURE);
}
for (;;) {
printf("epoll_wait \n");
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_wait");
exit(EXIT_FAILURE);
}
printf("new msg \n");
for (int n = 0; n < nfds; n++) {
if (events[n].data.fd == listenfd) {
conn_sock = accept(listenfd, (struct sockaddr*) &address,
(socklen_t*) &addrlen);
if (conn_sock < 0) {
perror("accept");
exit(EXIT_FAILURE);
}
setnonblocking(conn_sock);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
} else {
do_use_fd(events[n].data.fd, buffer);
}
}
}
shutdown(listenfd, SHUT_RDWR);
return EXIT_SUCCESS;
}
测试 : telnet 127.0.0.1 8080
可以打开2个终端来测试。