FD_WRITE 和 FD_READ的触发条件

FD_WRITE触发条件:
1.client 通过connect(WSAConnect)首次和server建立连接时,在client端会触发FD_WRITE事件
2.server通过accept(WSAAccept)接受client连接请求时,在server端会触发FD_WRITE事件
3.send(WSASend)/sendto(WSASendTo)发送失败返回WSAEWOULDBLOCK,并且当缓冲区有可用空间时,则会触发FD_WRITE事件
第1.2条其实是同一种情况,在第一次建立连接时,C/S端都会触发一个FD_WRITE事件。
主要是3这种情况:send出去的数据其实都先存在winsock的发送缓冲区中,然后才发送出去,如果缓冲区满了,那么再调用send(WSASend,sendto,WSASendTo)的话,就会返回一个 WSAEWOULDBLOCK的错误码,接下来随着发送缓冲区中的数据被发送出去,缓冲区中出现可用空间时,一个 FD_WRITE 事件才会被触发,这里比较容易混淆的是 FD_WRITE 触发的前提是  缓冲区要先被充满然后随着数据的发送又出现可用空间 ,而不是缓冲区中有可用空间,


因此,作为一个应用程序,自收到首条FD_WRITE消息开始,便应认为自己必然能在一
个套接字上发出数据,直至一个send、WSASend、sendto或WSASendTo返回套接字错误
WSAEWOULDBLOCK。经过了这样的失败以后,要再用另一条FD_WRITE通知应用程序再
次发送数据。


FD_READ事件触发条件: 
1.在数据到达socket后,并且从来没有触发过FD_READ(也就是最开始的阶段) 
2.在数据到达socket后,并且前一个recv()调用后 
3.调用recv()后,缓冲区还有未读完的数据

FD_READ过程如下: 
1.100 bytes 数据到达,winsock2发出FD_READ 
2.程序用recv()只读入50 bytes,还剩下50 bytes 
3.winsock2继续发出FD_READ消息

recv()返回WSAEWOULDBLOCK的情况: 
1.有数据到达,FD_READ触发,该消息加入程序的消息队列 
2.在还没处理该消息前,程序就把数据recv()了 
3.等到处理该FD_READ消息时,程序调用recv()就会返回WSAEWOULDBLOCK(因为数据在这之前就recv()了)

FD_READ注意: 
1.winsock2发出一个FD_READ后,如果程序没有用recv(),即使还有数据没接收FD_READ也不会再触发另一个FD_READ,要等到recv()调用后FD_READ才会发出。 
2.对一个FD_READ多次recv()的情形:如果程序对一个FD_READ多次recv()将会造成触发多个空的FD_READ,所以程序在第2次recv()前要关掉FD_READ(可以使用WSAAsynSelect关掉FD_READ),然后再多次recv()。 

3.recv()返回WSAECONNABORTED,WSAECONNRESET...等消息,可以不做任何处理,可以等到FD_CLOSE事件触发时再处理

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是以函数形式实现监测/sys/class/gpio/gpio2是否有中断发生的C语言代码,其中中断触发条件为both: ```c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <poll.h> #define GPIO_PATH "/sys/class/gpio/gpio2/" int gpio_init() { int fd, len; char buf[64]; // 导出GPIO fd = open("/sys/class/gpio/export", O_WRONLY); if (fd < 0) { perror("gpio export open failed"); return -1; } len = snprintf(buf, sizeof(buf), "%d", 2); if (write(fd, buf, len) < 0) { perror("gpio export write failed"); return -1; } close(fd); // 设置GPIO方向为输入 fd = open(GPIO_PATH "direction", O_WRONLY); if (fd < 0) { perror("gpio direction open failed"); return -1; } if (write(fd, "in", 2) < 0) { perror("gpio direction write failed"); return -1; } close(fd); return 0; } int gpio_wait_for_interrupt(int edge) { int fd, ret; char buf[64]; struct pollfd pfd; fd = open(GPIO_PATH "value", O_RDONLY); if (fd < 0) { perror("gpio value open failed"); return -1; } // 设置中断触发条件 snprintf(buf, sizeof(buf), "%d", edge); fd = open(GPIO_PATH "edge", O_WRONLY); if (fd < 0) { perror("gpio edge open failed"); return -1; } if (write(fd, buf, sizeof(buf)) < 0) { perror("gpio edge write failed"); return -1; } close(fd); // 等待中断事件 pfd.fd = fd; pfd.events = POLLPRI; while (1) { ret = poll(&pfd, 1, -1); if (ret < 0) { perror("gpio poll failed"); return -1; } if (pfd.revents & POLLPRI) { // 中断事件发生 lseek(fd, 0, SEEK_SET); // 重置文件指针 read(fd, buf, sizeof(buf)); // 清除中断标志 return 0; } } } int main() { int ret; // 初始化GPIO ret = gpio_init(); if (ret < 0) { return -1; } // 监测中断事件 while (1) { ret = gpio_wait_for_interrupt(2); // 2表示both if (ret < 0) { return -1; } printf("Interrupt occurred!\n"); } return 0; } ``` 注意,该代码需要以root权限运行。同时,为了方便测试,该代码只监测了GPIO2的中断事件,如果需要监测其他GPIO的中断事件,需要修改相应的代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值