linuxepoll和socket非阻塞讀

 

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, 2060);

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代碼:

 

view sourceprint?

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 */

相關文章
相關標籤/搜索