linux version: Linux version 2.6.32-5-686 (Debian 2.6.32-48squeeze4) (dannf@debian.org) (gcc version 4.3.5 (Debian 4.3.5-4) ) #1 SMP Mon Sep 23 23:00:18 UTC 2013html
noblock測試代碼:linux
epoll使用的是邊緣觸發模式nginx
view sourceprint?socket
01.
#include <stdio.h>
測試
02.
#include <sys/types.h>
.net
03.
#include <sys/socket.h>
debug
04.
#include <unistd.h>
unix
05.
#include <fcntl.h>
code
06.
#include <sys/epoll.h>
htm
07.
#include <netinet/in.h>
08.
#include <arpa/inet.h>
09.
#include <sys/un.h>
10.
#include <sys/ioctl.h>
11.
#include <string.h>
12.
#include <time.h>
13.
#include <sys/time.h>
14.
#include <errno.h>
15.
16.
int
main()
17.
{
18.
int
epoll_fp;
19.
int
srv;
20.
int
cli;
21.
struct sockaddr_in srv_addr;
22.
struct sockaddr_in cli_addr;
23.
struct epoll_event event;
24.
socklen_t len;
25.
epoll_fp = epoll_create(
1024
);
26.
27.
memset(&srv_addr,
0
, sizeof(struct sockaddr_in));
28.
inet_aton(
"127.0.0.1"
, &(srv_addr.sin_addr));
29.
srv_addr.sin_port = htons(
4455
);
30.
srv = socket(AF_INET, SOCK_STREAM,
0
);
31.
setsockopt(srv, SOL_SOCKET, SO_REUSEADDR,
32.
(
void
*)&len, sizeof(len));
33.
fcntl(srv, F_SETFL, fcntl(srv, F_GETFL) | O_NONBLOCK);
34.
bind(srv, (struct sockaddr *) &srv_addr,
35.
(socklen_t) sizeof(struct sockaddr_in));
36.
listen(srv,
100
);
37.
38.
event.events = EPOLLIN | EPOLLET;
39.
event.data.fd = srv;
40.
epoll_ctl(epoll_fp, EPOLL_CTL_ADD, srv, &event);
41.
42.
for
(;;) {
43.
struct epoll_event events[
20
];
44.
int
i, nfds;
45.
nfds = epoll_wait(epoll_fp, events,
20
,
60
);
46.
for
(i =
0
; i < nfds; i++) {
47.
if
(events[i].data.fd == srv) {
48.
int
cli;
49.
socklen_t len = sizeof(struct sockaddr_in);
50.
while
((cli = accept(srv, (struct sockaddr *)&cli_addr, &len)) >
0
) {
51.
fcntl(cli, F_SETFL, fcntl(cli, F_GETFL) | O_NONBLOCK);
52.
event.events = EPOLLIN | EPOLLET;
53.
event.data.fd = cli;
54.
epoll_ctl(epoll_fp, EPOLL_CTL_ADD, cli, &event);
55.
}
56.
if
(cli <
0
) {
57.
printf(
"accept %s\n"
, strerror(errno));
58.
}
59.
}
60.
else
{
61.
char
buffer[
4096
];
62.
int
len;
63.
int
fp = events[i].data.fd;
64.
65.
printf(
"client:%d start-------------\n"
, fp);
66.
while
((len = recv(fp, buffer, sizeof(buffer),
0
)) >=
0
) {
67.
if
(len >
0
) {
68.
printf(
"%s"
, buffer);
69.
}
70.
if
(len ==
0
) {
71.
printf(
"read len = 0\n"
);
72.
break
;
73.
}
74.
}
75.
if
(len <
0
) {
76.
printf(
"client:%d error:%s\n"
, cli, strerror(errno));
77.
}
78.
79.
printf(
"client:%d end---------------\n"
, fp);
80.
}
81.
}
82.
}
83.
84.
return
0
;
85.
}
86.
87.
88.
--------------------------------總結-------------------------------------
epoll_wait得到事件
{
a. 處理客戶端鏈接請求,創建鏈接
b. 讀客戶端發送數據
}
在沒有鏈接時,accept不會阻塞,直接返回,返回值小於0
errno等於EAGINE
strerror(errno) -----> Resource temporarily unavailable
在讀到沒有可讀數據時候 recv返回值小於0
errno等於EAGINE
strerror(errno) -----> Resource temporarily unavailable
在客戶端關閉鏈接時,會出現一個可讀事件,recv返回值等於0
注意!!!!!!!!
個人代碼沒有處理errno = EINETR--------------->interrupted system call錯誤
能夠看一下nginx的代碼,看他是怎樣處理這個錯誤的
--------------------------------------------------------------------------------總結結束分割線-----------------------------------------------------------------------------------------------------------------
最後看一下nginx怎樣讀客戶端發送數據的。
下面是ngx_recv.c代碼:
001.
/*
002.
* Copyright (C) Igor Sysoev
003.
* Copyright (C) Nginx, Inc.
004.
*/
005.
006.
007.
#include <ngx_config.h>
008.
#include <ngx_core.h>
009.
#include <ngx_event.h>
010.
011.
012.
#
if
(NGX_HAVE_KQUEUE)
013.
014.
ssize_t
015.
ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
016.
{
017.
ssize_t n;
018.
ngx_err_t err;
019.
ngx_event_t *rev;
020.
021.
rev = c->read;
022.
023.
if
(ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
024.
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log,
0
,
025.
"recv: eof:%d, avail:%d, err:%d"
,
026.
rev->pending_eof, rev->available, rev->kq_errno);
027.
028.
if
(rev->available ==
0
) {
029.
if
(rev->pending_eof) {
030.
rev->ready =
0
;
031.
rev->eof =
1
;
032.
033.
if
(rev->kq_errno) {
034.
rev->error =
1
;
035.
ngx_set_socket_errno(rev->kq_errno);
036.
037.
return
ngx_connection_error(c, rev->kq_errno,
038.
"kevent() reported about an closed connection"
);
039.
}
040.
041.
return
0
;
042.
043.
}
else
{
044.
rev->ready =
0
;
045.
return
NGX_AGAIN;
046.
}
047.
}
048.
}
049.
050.
do
{
051.
n = recv(c->fd, buf, size,
0
);
052.
053.
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log,
0
,
054.
"recv: fd:%d %d of %d"
, c->fd, n, size);
055.
056.
if
(n >=
0
) {
057.
if
(ngx_event_flags & NGX_USE_KQUEUE_EVENT) {
058.
rev->available -= n;
059.
060.
/*
061.
* rev->available may be negative here because some additional
062.
* bytes may be received between kevent() and recv()
063.
*/
064.
065.
if
(rev->available <=
0
) {
066.
if
(!rev->pending_eof) {
067.
rev->ready =
0
;
068.
}
069.
070.
if
(rev->available <
0
) {
071.
rev->available =
0
;
072.
}
073.
}
074.
075.
if
(n ==
0
) {
076.
077.
/*
078.
* on FreeBSD recv() may return 0 on closed socket
079.
* even if kqueue reported about available data
080.
*/
081.
082.
rev->eof =
1
;
083.
rev->available =
0
;
084.
}
085.
086.
return
n;
087.
}
088.
089.
if
((size_t) n < size) {
090.
rev->ready =
0
;
091.
}
092.
093.
if
(n ==
0
) {
094.
rev->eof =
1
;
095.
}
096.
097.
return
n;
098.
}
099.
100.
err = ngx_socket_errno;
101.
102.
if
(err == NGX_EAGAIN || err == NGX_EINTR) {
103.
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
104.
"recv() not ready"
);
105.
n = NGX_AGAIN;
106.
107.
}
else
{
108.
n = ngx_connection_error(c, err,
"recv() failed"
);
109.
break
;
110.
}
111.
112.
}
while
(err == NGX_EINTR);
113.
114.
rev->ready =
0
;
115.
116.
if
(n == NGX_ERROR) {
117.
rev->error =
1
;
118.
}
119.
120.
return
n;
121.
}
122.
123.
#
else
/* ! NGX_HAVE_KQUEUE */
124.
125.
ssize_t
126.
ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size)
127.
{
128.
ssize_t n;
129.
ngx_err_t err;
130.
ngx_event_t *rev;
131.
132.
rev = c->read;
133.
134.
do
{
135.
n = recv(c->fd, buf, size,
0
);
136.
137.
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log,
0
,
138.
"recv: fd:%d %d of %d"
, c->fd, n, size);
139.
140.
if
(n ==
0
) {
141.
rev->ready =
0
;
142.
rev->eof =
1
;
143.
return
n;
144.
145.
}
else
if
(n >
0
) {
146.
147.
if
((size_t) n < size
148.
&& !(ngx_event_flags & NGX_USE_GREEDY_EVENT))
149.
{
150.
rev->ready =
0
;
151.
}
152.
153.
return
n;
154.
}
155.
156.
err = ngx_socket_errno;
157.
158.
if
(err == NGX_EAGAIN || err == NGX_EINTR) {
159.
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err,
160.
"recv() not ready"
);
161.
n = NGX_AGAIN;
162.
163.
}
else
{
164.
n = ngx_connection_error(c, err,
"recv() failed"
);
165.
break
;
166.
}
167.
168.
}
while
(err == NGX_EINTR);
169.
170.
rev->ready =
0
;
171.
172.
if
(n == NGX_ERROR) {
173.
rev->error =
1
;
174.
}
175.
176.
return
n;
177.
}
178.
179.
#endif
/* NGX_HAVE_KQUEUE */