Linux网络编程中EAGAIN错误和EINTR错误

在Linux环境下开发经常会碰到很多错误(设置errno),其中EAGAIN是其中比较常见的一个错误(比如用在非阻塞操作中)。
    从字面上来看,是提示再试一次。这个错误经常出现在当应用程序进行一些非阻塞(non-blocking)操作(对文件或socket)的时候。例如,以O_NONBLOCK的标志打开文件/socket/FIFO,如果你连续做read操作而没有数据可读。此时程序不会阻塞起来等待数据准备就绪返回,read函数会返回一个错误EAGAIN,提示你的应用程序现在没有数据可读请稍后再试。

    又例如,当一个系统调用(比如fork)因为没有足够的资源(比如虚拟内存)而执行失败,返回EAGAIN提示其再调用一次(也许下次就能成功)。

Linux - 非阻塞socket编程处理EAGAIN错误
 在linux进行非阻塞的socket接收数据时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN),这是什么意思?
 这表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以。对非阻塞socket而言,EAGAIN不是一种错误。在VxWorks和Windows上,EAGAIN的名字叫做EWOULDBLOCK。


EINTR错误:

慢系统调用(slow system call):此术语适用于那些可能永远阻塞的系统调用。永远阻塞的系统调用是指调用有可能永远无法返回,多数网络支持函数都属于这一类。如:若没有客户连接到服务器上,那么服务器的accept调用就没有返回的保证。

EINTR错误的产生ÿ

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
好的,这是一个使用epoll实现的简单的Linux网络编程例子: ```c #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/epoll.h> #define MAX_EVENTS 1024 #define PORT 12345 int setnonblocking(int sockfd) { int flags = fcntl(sockfd, F_GETFL, 0); if (flags == -1) { return -1; } flags |= O_NONBLOCK; if (fcntl(sockfd, F_SETFL, flags) == -1) { return -1; } return 0; } int main(int argc, char *argv[]) { int listenfd, connfd, nfds, epollfd; ssize_t n; char buf[1024]; struct sockaddr_in servaddr, cliaddr; struct epoll_event ev, events[MAX_EVENTS]; // 创建监听socket,绑定地址和端口 listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(PORT); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, 5); // 创建epoll epollfd = epoll_create1(0); if (epollfd == -1) { perror("epoll_create1"); exit(EXIT_FAILURE); } // 设置监听socket为非阻塞 if (setnonblocking(listenfd) < 0) { perror("setnonblocking"); exit(EXIT_FAILURE); } // 添加监听socket事件到epoll ev.events = EPOLLIN | EPOLLET; ev.data.fd = listenfd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) { perror("epoll_ctl: listenfd"); exit(EXIT_FAILURE); } // 循环处理epoll事件 for (;;) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_wait"); exit(EXIT_FAILURE); } for (int i = 0; i < nfds; i++) { if (events[i].data.fd == listenfd) { // 新连接 socklen_t clilen = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen); if (connfd == -1) { perror("accept"); exit(EXIT_FAILURE); } // 设置连接socket为非阻塞 if (setnonblocking(connfd) < 0) { perror("setnonblocking"); exit(EXIT_FAILURE); } // 添加连接socket事件到epoll ev.events = EPOLLIN | EPOLLOUT | EPOLLET; ev.data.fd = connfd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev) == -1) { perror("epoll_ctl: connfd"); exit(EXIT_FAILURE); } // 打印新连接的客户端地址 printf("Accepted connection from %s:%d\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port)); } else { // 已连接 if (events[i].events & EPOLLIN) { // 可读 while ((n = read(events[i].data.fd, buf, sizeof(buf))) > 0) { // 处理读取到的数据 // ... } if (n == 0) { // 对方关闭连接 close(events[i].data.fd); printf("Closed connection on descriptor %d\n", events[i].data.fd); } else if (errno != EAGAIN && errno != EINTR) { // 发生错误 perror("read error"); close(events[i].data.fd); } } else if (events[i].events & EPOLLOUT) { // 可写 // 发送数据到连接socket // ... } else { // 其他事件 printf("Unknown event: %d\n", events[i].events); } } } } // 关闭监听socket和epoll close(listenfd); close(epollfd); return 0; } ``` 这个例子使用epoll监听TCP连接事件,支持EPOLLET边缘触发模式和非阻塞IO。当有新连接到来时,将连接socket添加到epoll,并打印客户端地址;当连接socket可读或可写时,分别处理读取和发送数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值