forked from Junbo-Zheng/cSocket
-
Notifications
You must be signed in to change notification settings - Fork 0
/
epoll.c
128 lines (108 loc) · 3.94 KB
/
epoll.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#define BACKLOG 5
#define BUFF_SIZE 200
#define DEFAULT_PORT 6666
#define MAX_EVENTS 10
int main(int argc, char* argv[])
{
int SERVER_PORT = DEFAULT_PORT;
if (argc > 2)
printf("param err:\nUsage:\n\t%s port | %s\n\n", argv[0], argv[0]);
if (argc == 2) SERVER_PORT = atoi(argv[1]);
int nbytes;
char buffer[BUFF_SIZE];
int servSocket, cliSocket;
socklen_t addrLen = 0;
struct sockaddr_in servAddr = { 0 };
struct sockaddr_in cliAddr = { 0 };
struct epoll_event ev, readyEvents[MAX_EVENTS];
int nfds, epollfd;
if ((servSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("socket err");
exit(1);
}
int optval = 1;
if (setsockopt(servSocket, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval))
< 0) {
perror("setsockopt");
exit(0);
}
bzero(&servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(SERVER_PORT);
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(servSocket, (struct sockaddr*)&servAddr, sizeof(servAddr)) < 0) {
perror("bind");
exit(1);
}
if (listen(servSocket, BACKLOG) < 0) {
perror("listen");
exit(1);
}
printf("Listen Port: %d\nListening ...\n", SERVER_PORT);
// 创建一个epoll实例
if ((epollfd = epoll_create1(0)) == -1) {
perror("epoll_create");
exit(1);
}
// ev是一个临时的变量,设置关心的描述符和关心的事件,然后把此结构与epoll实例绑定
ev.events = EPOLLIN;
ev.data.fd = servSocket;
// 给epoll实例感兴趣列表添加一个事件
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, servSocket, &ev) == -1) {
perror("epoll_ctl");
exit(1);
}
for (;;) {
// 等待epollfd表示的epoll实例中的事件变化,返回准备好的事件集合readyEvents
if ((nfds = epoll_wait(epollfd, readyEvents, MAX_EVENTS, -1)) == -1) {
perror("epoll_wait");
exit(1);
}
for (int n = 0; n < nfds; n++) {
// 有新连接到来了
if (readyEvents[n].data.fd == servSocket) {
cliSocket
= accept(servSocket, (struct sockaddr*)&cliAddr, &addrLen);
if (cliSocket == -1) {
perror("accept");
exit(1);
}
printf("\nNew client connections client[%d] %s:%d\n", cliSocket,
inet_ntoa(cliAddr.sin_addr), ntohs(cliAddr.sin_port));
ev.events = EPOLLIN | EPOLLET; // 设置关心可读状态和边缘触发模式
ev.data.fd = cliSocket;
// 把心连接描述符加到epoll实例感兴趣列表
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, cliSocket, &ev) == -1) {
perror("epoll_ctl: cliSocket");
exit(1);
}
} else {
// 已有连接发数据过来了,开始接收数据~
cliSocket = readyEvents[n].data.fd;
memset(buffer, 0, BUFF_SIZE);
/* recv data */
nbytes = recv(cliSocket, buffer, sizeof(buffer), 0);
if (nbytes < 0) {
perror("recv");
continue;
} else if (nbytes == 0) {
printf("\nDisconnect fd[%d]\n", cliSocket);
close(cliSocket);
// 关闭文件描述符epoll实例会自动移除此描述符,
// 也可以使用EPOLL_CTL_DEL手动移除
} else {
printf("\nFrom fd[%d]", cliSocket);
printf("\nRecv: %sLength: %d\n\n", buffer, nbytes);
}
}
}
}
// return 0;
}