【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
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 2013
noblock测试代码:
epoll使用的是边缘触发模式
01.#include <stdio.h>
02.#include <sys/types.h>
03.#include <sys/socket.h>
04.#include <unistd.h>
05.#include <fcntl.h>
06.#include <sys/epoll.h>
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 */
来源:oschina
链接:https://my.oschina.net/u/4000302/blog/3099343