epoll相对于poll和select这两个多路复用的I/O模型更加的高效。epoll的函数很简单,麻烦的地方在于水平出发和边沿触发。
ET(边沿)只是在状态反转时触发,比如从不可读到可读。而LT(水平)就是如果可读,就会一直触发。所以在使用ET的时候要做一些额外的处理,比如可读的,一直把缓冲区读完,进入不可读状态,下次来数据才会触发。
下面贴出代码,只是一个简单的练习的例子
socketheads.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
#ifndef SOCKETHEADS_H
#define SOCKETHEADS_H
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif //SOCKETHEADS_H
|
zepoll.h
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
|
#ifndef EPOLL_H
#define EPOLL_H
#include <sys/epoll.h>
#include <unistd.h>
/**
* @brief The Epoll class 对epoll的封装
*/
class
Epoll
{
public
:
/**
*
*/
enum
EPOLL_OP
{
ADD
=
EPOLL_CTL_ADD
,
MOD
=
EPOLL_CTL_MOD
,
DEL
=
EPOLL_CTL_DEL
}
;
/**
* 最大的连接数和最大的回传事件数
*/
Epoll
(
int
_max
=
30
,
int
maxevents
=
20
)
;
~
Epoll
(
)
;
int
create
(
)
;
int
add
(
int
fd
,
epoll_event
*
event
)
;
int
mod
(
int
fd
,
epoll_event
*
event
)
;
int
del
(
int
fd
,
epoll_event
*
event
)
;
void
setTimeout
(
int
timeout
)
;
void
setMaxEvents
(
int
maxevents
)
;
int
wait
(
)
;
const
epoll_event
*
events
(
)
const
;
const
epoll_event
&
operator
[
]
(
int
index
)
{
return
backEvents
[
index
]
;
}
private
:
bool
isValid
(
)
const
;
int
max
;
int
epoll_fd
;
int
epoll_timeout
;
int
epoll_maxevents
;
epoll_event
*
backEvents
;
}
;
#endif //EPOLL_H
|
zepoll.cpp
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
|
#include "zepoll.h"
Epoll
::
Epoll
(
int
_max
,
int
maxevents
)
:
max
(
_max
)
,
epoll_fd
(
-
1
)
,
epoll_timeout
(
0
)
,
epoll_maxevents
(
maxevents
)
,
backEvents
(
0
)
{
}
Epoll
::
~
Epoll
(
)
{
if
(
isValid
(
)
)
{
close
(
epoll_fd
)
;
}
delete
[
]
backEvents
;
}
inline
bool
Epoll
::
isValid
(
)
const
{
return
epoll_fd
>
0
;
}
inline
void
Epoll
::
setTimeout
(
int
timeout
)
{
epoll_timeout
=
timeout
;
}
inline
void
Epoll
::
setMaxEvents
(
int
maxevents
)
{
epoll_maxevents
=
maxevents
;
}
inline
const
epoll_event
*
Epoll
::
events
(
)
const
{
return
backEvents
;
}
int
Epoll
::
create
(
)
{
epoll_fd
=
::
epoll_create
(
max
)
;
if
(
isValid
(
)
)
{
backEvents
=
new
epoll_event
[
epoll_maxevents
]
;
}
return
epoll_fd
;
}
int
Epoll
::
add
(
int
fd
,
epoll_event
*
event
)
{
if
(
isValid
(
)
)
{
return
::
epoll_ctl
(
epoll_fd
,
ADD
,
fd
,
event
)
;
}
return
-
1
;
}
int
Epoll
::
mod
(
int
fd
,
epoll_event
*
event
)
{
if
(
isValid
(
)
)
{
return
::
epoll_ctl
(
epoll_fd
,
MOD
,
fd
,
event
)
;
}
return
-
1
;
}
int
Epoll
::
del
(
int
fd
,
epoll_event
*
event
)
{
if
(
isValid
(
)
)
{
return
::
epoll_ctl
(
epoll_fd
,
DEL
,
fd
,
event
)
;
}
return
-
1
;
}
int
Epoll
::
wait
(
)
{
if
(
isValid
(
)
)
{
return
::
epoll_wait
(
epoll_fd
,
backEvents
,
epoll_maxevents
,
epoll_timeout
)
;
}
return
-
1
;
}
|
task.h
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
|
/********************************************************************
* author 周翔
* e-mail 604487178@qq.com
* blog http://blog.youkuaiyun.com/zhx6044
**********************************************************************/
#ifndef TASK_H
#define TASK_H
#include <string>
#include <socketheads.h>
/**
* @brief The Task class 任务类
*/
class
Task
{
public
:
typedef
enum
{
CONNECT
=
0
,
DISCONNECT
,
TALKING
}
TASKFLAG
;
Task
(
const
std
::
string
&message
,
TASKFLAG
flag
=
TALKING
)
;
const
std
::
string
&
getMessage
(
)
const
;
TASKFLAG
getFlag
(
)
const
;
void
setIP
(
in_addr
_ip
)
;
int
getS_fd
(
)
const
;
void
setS_fd
(
int
_fd
)
;
std
::
string
getData
(
)
const
;
private
:
std
::
string
m_message
;
TASKFLAG
m_flag
;
in_addr
ip
;
int
s_fd
;
}
;
#endif // TASK_H
|
task.cpp
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
|
/********************************************************************
* author 周翔
* e-mail 604487178@qq.com
* blog http://blog.youkuaiyun.com/zhx6044
**********************************************************************/
#include "task.h"
Task
::
Task
(
const
std
::
string
&message
,
TASKFLAG
flag
)
:
m_message
(
message
)
,
m_flag
(
flag
)
{
}
const
std
::
string
&
Task
::
getMessage
(
)
const
{
return
m_message
;
}
Task
::
TASKFLAG
Task
::
getFlag
(
)
const
{
return
m_flag
;
}
void
Task
::
setIP
(
in_addr
_ip
)
{
ip
=
_ip
;
}
int
Task
::
getS_fd
(
)
const
{
return
s_fd
;
}
void
Task
::
setS_fd
(
int
_fd
)
{
s_fd
=
_fd
;
}
std
::
string
Task
::
getData
(
)
const
{
std
::
string
re
;
if
(
m_flag
==
CONNECT
)
{
re
=
::
inet_ntoa
(
ip
)
+
std
::
string
(
"----->"
)
+
"CONNECT! "
+
m_message
;
}
else
{
if
(
m_flag
==
DISCONNECT
)
{
re
=
::
inet_ntoa
(
ip
)
+
std
::
string
(
"----->"
)
+
"DISCONNECT "
+
m_message
;
;
}
else
{
re
=
::
inet_ntoa
(
ip
)
+
std
::
string
(
"----->Talk:"
)
+
m_message
;
}
}
return
re
;
}
|
epoll_server.h
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
|
#ifndef EPOLL_SERVER_H
#define EPOLL_SERVER_H
#include <map>
#include <list>
#include "zepoll.h"
#include "socketheads.h"
#include "task.h"
typedef
std
::
pair
<
int
,
in_addr
>
FDtoIP
;
/**
* @brief The Epoll_server class 服务器
*/
class
Epoll_server
{
public
:
Epoll_server
(
int
port
)
;
~
Epoll_server
(
)
;
int
bind
(
)
;
int
listen
(
)
;
void
poweroff
(
)
;
bool
states
(
)
const
;
private
:
enum
{
BLOCKLOG
=
5
}
;
bool
isValid
(
)
const
;
int
acceptSocketEpoll
(
)
;
int
readSocketEpoll
(
const
epoll_event
&ev
)
;
int
writeSocketEpoll
(
const
epoll_event
&ev
)
;
void
doTask
(
const
Task
&t
)
;
int
_port
;
int
server_socket_fd
;
Epoll
*
_epoll
;
sockaddr_in
server_addr
;
sockaddr_in
client_addr
;
epoll_event
m_event
;
bool
on
;
static
int
setNonblocking
(
int
socket_fd
)
;
std
::
list
<
FDtoIP
>
fd_IP
;
}
;
#endif //EPOLL_SERVER_H
|
epoll_server.cpp
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
|
#include "epoll_server.h"
#include <iostream>
//static char welcom[] = "welcom to my epoll_server";
//static char sorry[] = "Sorry! This is a simple demo,so not any function!";
//static char buf[BUFSIZ];
Epoll_server
::
Epoll_server
(
int
port
)
:
_port
(
port
)
,
server_socket_fd
(
-
1
)
,
_epoll
(
0
)
,
on
(
true
)
{
}
Epoll_server
::
~
Epoll_server
(
)
{
if
(
isValid
(
)
)
{
::
close
(
server_socket_fd
)
;
}
delete
_epoll
;
}
inline
bool
Epoll_server
::
isValid
(
)
const
{
return
server_socket_fd
>
0
;
}
inline
void
Epoll_server
::
poweroff
(
)
{
on
=
false
;
}
inline
bool
Epoll_server
::
states
(
)
const
{
return
on
;
}
int
Epoll_server
::
setNonblocking
(
int
socket_fd
)
{
int
opts
;
opts
=
fcntl
(
socket_fd
,
F_GETFL
)
;
if
(
opts
<
0
)
{
return
-
1
;
}
else
{
opts
=
opts
|
O_NONBLOCK
;
if
(
fcntl
(
socket_fd
,
F_SETFL
,
opts
)
<
0
)
{
return
-
1
;
}
}
return
0
;
}
void
Epoll_server
::
doTask
(
const
Task
&t
)
{
std
::
list
<
FDtoIP
>
::
iterator
ite
=
fd_IP
.
begin
(
)
;
std
::
list
<
FDtoIP
>
::
iterator
ite1
=
fd_IP
.
end
(
)
;
for
(
;
ite
!=
fd_IP
.
end
(
)
;
++
ite
)
{
if
(
(
*
ite
)
.
first
!=
t
.
getS_fd
(
)
)
{
memset
(
&m_event
,
'\0'
,
sizeof
(
m_event
)
)
;
m_event
.
events
=
EPOLLOUT
|
EPOLLET
;
Task
*
c
=
new
Task
(
t
)
;
c
->
setS_fd
(
(
*
ite
)
.
first
)
;
m_event
.
data
.
ptr
=
static_cast
<
void
*
>
(
c
)
;
_epoll
->
mod
(
(
*
ite
)
.
first
,
&m_event
)
;
}
else
{
ite1
=
ite
;
}
}
if
(
t
.
getFlag
(
)
==
Task
::
DISCONNECT
)
{
if
(
ite1
!=
fd_IP
.
end
(
)
)
{
fd_IP
.
erase
(
ite1
)
;
}
}
}
/**
* @brief Epoll_server::acceptSocketEpoll 有用户接入
* @return
*/
int
Epoll_server
::
acceptSocketEpoll
(
)
{
socklen_t
len
=
sizeof
(
struct
sockaddr_in
)
;
int
connect_fd
;
while
(
(
connect_fd
=
::
accept
(
server_socket_fd
,
(
struct
sockaddr
*
)
(
&client_addr
)
,
&len
)
)
>
0
)
{
if
(
setNonblocking
(
connect_fd
)
<
0
)
{
::
close
(
connect_fd
)
;
continue
;
}
m_event
.
data
.
fd
=
connect_fd
;
m_event
.
events
=
EPOLLIN
|
EPOLLET
;
if
(
_epoll
->
add
(
connect_fd
,
&m_event
)
<
0
)
{
::
close
(
connect_fd
)
;
continue
;
}
else
{
fd_IP
.
push_back
(
FDtoIP
(
connect_fd
,
client_addr
.
sin_addr
)
)
;
Task
t
(
"come in"
,
Task
::
CONNECT
)
;
t
.
setIP
(
client_addr
.
sin_addr
)
;
t
.
setS_fd
(
connect_fd
)
;
doTask
(
t
)
;
}
}
if
(
connect_fd
==
-
1
&&
errno
!=
EAGAIN
&&
errno
!=
ECONNABORTED
&&
errno
!=
EPROTO
&&
errno
!=
EINTR
)
{
return
-
1
;
}
return
0
;
}
int
Epoll_server
::
readSocketEpoll
(
const
epoll_event
&ev
)
{
int
n
=
0
;
int
nread
=
0
;
char
buf
[
BUFSIZ
]
=
{
'\0'
}
;
while
(
(
nread
=
::
read
(
ev
.
data
.
fd
,
buf
+
n
,
BUFSIZ
-
1
)
)
>
0
)
{
n
+=
nread
;
}
if
(
nread
==
-
1
&&
errno
!=
EAGAIN
)
{
return
-
1
;
}
std
::
list
<
FDtoIP
>
::
iterator
ite
=
fd_IP
.
begin
(
)
;
for
(
;
ite
!=
fd_IP
.
end
(
)
;
++
ite
)
{
if
(
(
*
ite
)
.
first
==
ev
.
data
.
fd
)
{
break
;
}
}
if
(
nread
==
0
)
{
strcpy
(
buf
,
" disconet left "
)
;
Task
t
(
buf
,
Task
::
DISCONNECT
)
;
t
.
setIP
(
client_addr
.
sin_addr
)
;
t
.
setS_fd
(
(
*
ite
)
.
first
)
;
doTask
(
t
)
;
}
else
{
Task
t
(
buf
,
Task
::
TALKING
)
;
t
.
setIP
(
client_addr
.
sin_addr
)
;
t
.
setS_fd
(
(
*
ite
)
.
first
)
;
doTask
(
t
)
;
}
// Task *t = new Task(buf,Task::DISCONNECT);
// t->setIP((*ite).second);
// t->setS_fd((*ite).first);
// m_event.data.fd = ev.data.fd;
// m_event.events = ev.events;
return
0
;
//_epoll->mod(m_event.data.fd, &m_event);
}
int
Epoll_server
::
writeSocketEpoll
(
const
epoll_event
&ev
)
{
Task
*
t
=
static_cast
<
Task
*
>
(
ev
.
data
.
ptr
)
;
const
char
*
buf
=
t
->
getData
(
)
.
data
(
)
;
int
nwrite
=
0
,
data_size
=
strlen
(
buf
)
;
int
fd
=
t
->
getS_fd
(
)
;
int
n
=
data_size
;
delete
t
;
while
(
n
>
0
)
{
nwrite
=
::
write
(
fd
,
buf
+
data_size
-
n
,
n
)
;
if
(
nwrite
<
0
)
{
if
(
nwrite
==
-
1
&&
errno
!=
EAGAIN
)
{
return
-
1
;
}
break
;
}
n
-=
nwrite
;
}
memset
(
&m_event
,
'\0'
,
sizeof
(
m_event
)
)
;
// m_event.events &= ~EPOLLOUT;
m_event
.
events
=
EPOLLIN
|
EPOLLET
;
m_event
.
data
.
fd
=
fd
;
if
(
_epoll
->
mod
(
fd
,
&m_event
)
<
0
)
{
::
close
(
m_event
.
data
.
fd
)
;
return
-
1
;
}
return
0
;
}
/**
* @brief Epoll_server::bind
* @return
*/
int
Epoll_server
::
bind
(
)
{
server_socket_fd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
)
;
if
(
server_socket_fd
<
0
)
{
return
-
1
;
}
setNonblocking
(
server_socket_fd
)
;
_epoll
=
new
Epoll
(
)
;
if
(
_epoll
->
create
(
)
<
0
)
{
return
-
1
;
}
memset
(
&m_event
,
'\0'
,
sizeof
(
m_event
)
)
;
m_event
.
data
.
fd
=
server_socket_fd
;
m_event
.
events
=
EPOLLIN
|
EPOLLET
;
_epoll
->
add
(
server_socket_fd
,
&m_event
)
;
memset
(
&server_addr
,
0
,
sizeof
(
server_addr
)
)
;
server_addr
.
sin_family
=
AF_INET
;
server_addr
.
sin_addr
.
s_addr
=
htonl
(
INADDR_ANY
)
;
server_addr
.
sin_port
=
htons
(
_port
)
;
return
::
bind
(
server_socket_fd
,
(
struct
sockaddr
*
)
(
&server_addr
)
,
sizeof
(
struct
sockaddr
)
)
;
}
int
Epoll_server
::
listen
(
)
{
if
(
isValid
(
)
)
{
if
(
::
listen
(
server_socket_fd
,
BLOCKLOG
)
<
0
)
{
return
-
1
;
}
else
{
int
num
;
while
(
on
)
{
num
=
_epoll
->
wait
(
)
;
for
(
int
i
=
0
;
i
<
num
;
++
i
)
{
/**
* 接受连接的连接,把她加入到epoll中
*/
if
(
(
*
_epoll
)
[
i
]
.
data
.
fd
==
server_socket_fd
)
{
if
(
acceptSocketEpoll
(
)
<
0
)
{
break
;
}
continue
;
}
/**
* EPOLLIN event
*/
if
(
(
*
_epoll
)
[
i
]
.
events
&
EPOLLIN
)
{
if
(
readSocketEpoll
(
(
*
_epoll
)
[
i
]
)
<
0
)
{
break
;
}
continue
;
}
/**
* EPOLLOUT event
*/
if
(
(
*
_epoll
)
[
i
]
.
events
&
EPOLLOUT
)
{
if
(
writeSocketEpoll
(
(
*
_epoll
)
[
i
]
)
<
0
)
{
break
;
}
}
}
}
}
}
return
-
1
;
}
|
main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
|
#include "epoll_server.h"
#include <iostream>
int
main
(
int
/*argc*/
,
char
const
*
*
/*argv[]*/
)
{
std
::
cout
<<
"server"
<<
std
::
endl
;
Epoll
_server
s
(
18090
)
;
if
(
s
.
bind
(
)
<
0
)
{
return
-
1
;
}
return
s
.
listen
(
)
;
}
|
客户端用qt简单的写了一个
客户端服务端代码:epoll_chatroom.zip
FROM: http://love.junzimu.com/archives/2660