noblock测试代码:
epoll使用的是边缘触发模式
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #include <fcntl.h> #include <sys/epoll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/un.h> #include <sys/ioctl.h> #include <string.h> #include <time.h> #include <sys/time.h> #include <errno.h> int main() { int epoll_fp; int srv; int cli; struct sockaddr_in srv_addr; struct sockaddr_in cli_addr; struct epoll_event event; socklen_t len; epoll_fp = epoll_create(1024); memset(&srv_addr, 0, sizeof(struct sockaddr_in)); inet_aton("127.0.0.1", &(srv_addr.sin_addr)); srv_addr.sin_port = htons(4455); srv = socket(AF_INET, SOCK_STREAM, 0); setsockopt(srv, SOL_SOCKET, SO_REUSEADDR, (void *)&len, sizeof(len)); fcntl(srv, F_SETFL, fcntl(srv, F_GETFL) | O_NONBLOCK); bind(srv, (struct sockaddr *) &srv_addr, (socklen_t) sizeof(struct sockaddr_in)); listen(srv, 100); event.events = EPOLLIN | EPOLLET; event.data.fd = srv; epoll_ctl(epoll_fp, EPOLL_CTL_ADD, srv, &event); for(;;) { struct epoll_event events[20]; int i, nfds; nfds = epoll_wait(epoll_fp, events, 20, 60); for (i = 0; i < nfds; i++) { if (events[i].data.fd == srv) { int cli; socklen_t len = sizeof(struct sockaddr_in); while ((cli = accept(srv, (struct sockaddr *)&cli_addr, &len)) > 0) { fcntl(cli, F_SETFL, fcntl(cli, F_GETFL) | O_NONBLOCK); event.events = EPOLLIN | EPOLLET; event.data.fd = cli; epoll_ctl(epoll_fp, EPOLL_CTL_ADD, cli, &event); } if (cli < 0) { printf("accept %s\n", strerror(errno)); } } else { char buffer[4096]; int len; int fp = events[i].data.fd; printf("client:%d start-------------\n", fp); while ((len = recv(fp, buffer, sizeof(buffer), 0)) >= 0) { if (len > 0) { printf("%s", buffer); } if (len == 0) { printf("read len = 0\n"); break; } } if (len < 0) { printf("client:%d error:%s\n", cli, strerror(errno)); } printf("client:%d end---------------\n", fp); } } } return 0; }
epoll_wait获得事件
{
a. 处理客户端连接请求,建立连接
b. 读客户端发送数据
}
在没有连接时,accept不会阻塞,直接返回,返回值小于0
errno等于EAGINE
strerror(errno) -----> Resource temporarily unavailable
在读到没有可读数据时候 recv返回值小于0
errno等于EAGINE
在客户端关闭连接时,会出现一个可读事件,recv返回值等于0
注意!!!!!!!!
我的代码没有处理errno = EINETR--------------->interrupted system call错误
可以看一下nginx的代码,看他是怎样处理这个错误的
--------------------------------------------------------------------------------总结结束分割线-----------------------------------------------------------------------------------------------------------------
最后看一下nginx怎样读客户端发送数据的。
下面是ngx_recv.c代码:
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_event.h> #if (NGX_HAVE_KQUEUE) ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) { ssize_t n; ngx_err_t err; ngx_event_t *rev; rev = c->read; if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "recv: eof:%d, avail:%d, err:%d", rev->pending_eof, rev->available, rev->kq_errno); if (rev->available == 0) { if (rev->pending_eof) { rev->ready = 0; rev->eof = 1; if (rev->kq_errno) { rev->error = 1; ngx_set_socket_errno(rev->kq_errno); return ngx_connection_error(c, rev->kq_errno, "kevent() reported about an closed connection"); } return 0; } else { rev->ready = 0; return NGX_AGAIN; } } } do { n = recv(c->fd, buf, size, 0); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "recv: fd:%d %d of %d", c->fd, n, size); if (n >= 0) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { rev->available -= n; /* * rev->available may be negative here because some additional * bytes may be received between kevent() and recv() */ if (rev->available <= 0) { if (!rev->pending_eof) { rev->ready = 0; } if (rev->available < 0) { rev->available = 0; } } if (n == 0) { /* * on FreeBSD recv() may return 0 on closed socket * even if kqueue reported about available data */ rev->eof = 1; rev->available = 0; } return n; } if ((size_t) n < size) { rev->ready = 0; } if (n == 0) { rev->eof = 1; } return n; } err = ngx_socket_errno; if (err == NGX_EAGAIN || err == NGX_EINTR) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "recv() not ready"); n = NGX_AGAIN; } else { n = ngx_connection_error(c, err, "recv() failed"); break; } } while (err == NGX_EINTR); rev->ready = 0; if (n == NGX_ERROR) { rev->error = 1; } return n; } #else /* ! NGX_HAVE_KQUEUE */ ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size) { ssize_t n; ngx_err_t err; ngx_event_t *rev; rev = c->read; do { n = recv(c->fd, buf, size, 0); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, "recv: fd:%d %d of %d", c->fd, n, size); if (n == 0) { rev->ready = 0; rev->eof = 1; return n; } else if (n > 0) { if ((size_t) n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT)) { rev->ready = 0; } return n; } err = ngx_socket_errno; if (err == NGX_EAGAIN || err == NGX_EINTR) { ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, "recv() not ready"); n = NGX_AGAIN; } else { n = ngx_connection_error(c, err, "recv() failed"); break; } } while (err == NGX_EINTR); rev->ready = 0; if (n == NGX_ERROR) { rev->error = 1; } return n; } #endif /* NGX_HAVE_KQUEUE */
linux epoll和 socket非阻塞读,布布扣,bubuko.com
原文:http://blog.csdn.net/gamesofsailing/article/details/20535401