epoll詳解(四)-- LT模式例項
阿新 • • 發佈:2019-02-15
通過本文你會了解到:
1. epoll LT模式例項
2. 執行測試
約定
1. 格式為 /**/ 的註釋對程式的主要流程進行說明
2. 格式為 // 的註釋對程式的難懂語句進行說明
#include <stdio.h> // for printf()
#include <stdlib.h> // for exit()
#include <unistd.h> // for read() and write()
#include <sys/epoll.h> // for epoll
#include <sys/socket.h> // for epoll
#include <netinet/in.h> //struct sockaddr_in
#include <string.h> // memset
#include <fcntl.h> // fcntl
#include <errno.h> // errno
#define EPOLL_QUEUE_LEN 32 //監聽的最大連線數
#define BUF_SIZE 1024
static int listen_socket(int port)
{
int fd;
struct sockaddr_in sa;
fd = socket(AF_INET, SOCK_STREAM, 0 );
if(fd == -1) {
perror("socket");
return -1;
}
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
perror("bind");
close(fd);
return -1;
}
if(listen(fd, 5) == -1) {
perror("listen");
close(fd);
return -1;
}
return fd;
}
int main(int argc, char **argv)
{
struct epoll_event ev;
struct epoll_event events[EPOLL_QUEUE_LEN];
int epfd;
int sfd;
int nfds;
if(argc != 2) {
printf("usage: %s [port]\n", argv[0]);
exit(EXIT_FAILURE);
}
/*建立 epoll 例項*/
epfd = epoll_create(EPOLL_QUEUE_LEN);
if(epfd == -1) {
perror("epoll_create");
exit(EXIT_FAILURE);
}
/*對輸入port進行監聽*/
printf("server listen form port: %d\n", atoi(argv[1]));
sfd = listen_socket(atoi(argv[1]));
if(sfd == -1) {
printf("listen_socket failed\n");
exit(EXIT_FAILURE);
}
/*將server描述符新增到epoll中*/
ev.data.fd = sfd;
ev.events = EPOLLIN;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, sfd, &ev) == -1) {
perror("epoll_ctl");
exit(EXIT_FAILURE);
}
/*主迴圈*/
while(1) {
int i;
/*等待epoll例項中描述符有I/O事件發生*/
nfds = epoll_wait(epfd, events, EPOLL_QUEUE_LEN, -1);
for(i = 0; i < nfds; i++) {
if(events[i].events & (EPOLLERR | EPOLLHUP)) {
//EPOLLERR - 出現錯誤
//EPOLLHUP - 客戶端提前關閉連線(close by peer)
continue;
}
if(!(events[i].events & EPOLLIN)) { //不是IN操作
continue;
}
if(sfd == events[i].data.fd) {
/*有客戶端連入server*/
struct sockaddr_in in_addr;
socklen_t in_len;
int infd;
infd = accept(sfd, (struct sockaddr *)&in_addr, &in_len);
if(infd == -1) {
perror("accept");
continue;
}
ev.data.fd = infd;
ev.events = EPOLLIN;
if(epoll_ctl(epfd, EPOLL_CTL_ADD, infd, &ev) == -1) {
perror("epoll_ctl");
exit(EXIT_FAILURE);
}
printf("incoming client [fd=%d]\n", infd);
} else {
/*收到客戶端資料*/
ssize_t cnt;
char buf[BUF_SIZE];
memset(buf, 0, sizeof(buf));
cnt = read(events[i].data.fd, buf, sizeof(buf));
if(cnt == -1) {
perror("read");
} else if (cnt == 0) { //fd 被關閉
printf("remote close fd\n");
} else {
printf("receive data: %s\n", buf);
}
printf("close client [fd=%d]\n", events[i].data.fd);
close(events[i].data.fd);
}
}
}
close(sfd);
return 0;
}
執行測試
應用linux nc網路工具,詳細用法參見man nc。