linux epoll 非阻塞,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 2013

noblock测试代码:

epoll使用的是边缘触发模式

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

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

strerror(errno) -----> Resource temporarily unavailable

在客户端关闭连接时,会出现一个可读事件,recv返回值等于0

注意!!!!!!!!

我的代码没有处理errno = EINETR--------------->interrupted system call错误

可以看一下nginx的代码,看他是怎样处理这个错误的

--------------------------------------------------------------------------------总结结束分割线-----------------------------------------------------------------------------------------------------------------

最后看一下nginx怎样读客户端发送数据的。

下面是ngx_recv.c代码:

/*

* Copyright (C) Igor Sysoev

* Copyright (C) Nginx, Inc.

*/

#include

#include

#include

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值