Poll就是监控文件是否可读的一种机制,作用与select一样。
应用程序的调用函数如下:
int poll(struct pollfd *fds,nfds_t nfds, int timeout);
Poll机制会判断fds中的文件是否可读,如果可读则会立即返回,返回的值就是可读fd的数量,如果不可读,那么就进程就会休眠timeout这么长的时间,然后再来判断是否有文件可读,如果有,返回fd的数量,如果没有,则返回0.
使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问,这两个系统调用最终又会引发设备驱动中的poll()函数被执行
如果当前不可读(先调用驱动.poll确定是否可读,然后继续do_poll),那么在sys_poll->do_poll中当前进程就会睡眠在等待队列上,这个等待队列是由驱动程序提供的(就是poll_wait中传入的那个)。当可读的时候,驱动程序可能有一部分代码运行了(比如驱动的中断服务
程序),那么在这部分代码中,就会唤醒等待队列上的进程,也就是之前睡眠的那个,当那个进程被唤醒后do_poll会再一次的调用驱动程序的poll函数,这个时候应用程序就知道是可读的了。
Demo程序(一个线程中同时监听两个UDP客户程序的数据发送):
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
/// Handle poll input types
#define POLL_INPUT (POLLIN | POLLPRI)
/// Handle poll error types
#define POLL_ERROR (POLLERR | POLLHUP | POLLNVAL)
/// Handle pool output types
#define POLL_OUTPUT (POLLOUT)
/// Identify each physical interface
typedef enum FHandleVal
{
INTERFACE_UDP_DCP = 0,
INTERFACE_UDP_LTE,
INTERFACE_MAX_VAL
}
eFHandleVal;
static struct pollfd FDesc[INTERFACE_MAX_VAL];
static int rxUDPLTEInit();
static int rxUDPDCPInit();
static int rxLteUDPData(int fd);
static int rxDCPUDPData(int fd);
int rxUDPLTEInit()
{
struct sockaddr_in server_lte_addr;
/// UDP datagram socket
int sock_Lte_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock_Lte_fd < 0)
{
// oops
printf("UDP lte: RX socket failed %d, %s\n",
errno, strerror(errno));
sock_Lte_fd = -errno;
return -1;
}
memset(&server_lte_addr,0,sizeof(struct sockaddr_in));
server_lte_addr.sin_family = AF_INET;
server_lte_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_lte_addr.sin_port = htons(27358);
int rc = bind(sock_Lte_fd, (struct sockaddr *)&server_lte_addr, sizeof(server_lte_addr));
if (rc < 0)
{
// oops
printf("UDP: bind(%d, ANY) RX failed: %d, %s\n",
sock_Lte_fd, errno, strerror(errno));
close(sock_Lte_fd);
sock_Lte_fd = -errno;
}
else
{
printf("UDP: bind on RX port %d\n",27358);
}
return sock_Lte_fd;
}
int rxUDPDCPInit()
{
int sock_fd;
struct sockaddr_in server_addr;
struct sockaddr_in src_addr;
socklen_t client_len;
memset(&server_addr,0,sizeof(struct sockaddr_in));
if ((sock_fd = socket(AF_INET, SOCK_DGRAM,0)) < 0)
{
perror("socket create error\n");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(4004);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
printf("Ready bind 4004\n");
if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) < 0)
{
perror("bind socket error.\n");
exit(1);
}
return sock_fd;
}
int rxDCPUDPData(int fd)
{
int rcv_num = -1;
char rcv_buff[512];
struct sockaddr_in src_addr;
socklen_t client_len;
int encodeNum = -1;
BSM_t BSMData;
client_len = sizeof(struct sockaddr_in);
rcv_num= recvfrom(fd, rcv_buff, sizeof(rcv_buff), 0, (struct sockaddr*)&src_addr, &client_len);
if (rcv_num>0)
{
rcv_buff[rcv_num] = '\0';
printf("%s %d says: %s\n",inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port),rcv_buff);
}
else
{
perror("recv DCP Data error\n");
exit(1);
}
return 0;
}
int rxLteUDPData(int fd)
{
int rcv_num = -1;
char rcv_buff[512];
struct sockaddr_in src_addr;
socklen_t client_len;
client_len = sizeof(struct sockaddr_in);
rcv_num= recvfrom(fd, rcv_buff, sizeof(rcv_buff), 0, (struct sockaddr*)&src_addr, &client_len);
if (rcv_num>0)
{
rcv_buff[rcv_num] = '\0';
printf("%s %d says: %s\n",inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port),rcv_buff);
}else
{
perror("recv LTE-V Data error:");
exit(1);
}
}
int main(void)
{
FDesc[INTERFACE_UDP_LTE].fd = rxUDPLTEInit();
if (FDesc[INTERFACE_UDP_LTE].fd < 0) exit(1);
FDesc[INTERFACE_UDP_DCP].fd = rxUDPDCPInit();
if (FDesc[INTERFACE_UDP_DCP].fd < 0) exit(1);
// setup the poll events
FDesc[INTERFACE_UDP_DCP].events = POLL_INPUT;
FDesc[INTERFACE_UDP_LTE].events = POLL_INPUT;
while (1)
{
int Data = poll(FDesc, INTERFACE_MAX_VAL, 1000);
// poll status check
if (Data < 0)
{
// error
printf("Poll error %d '%s'\n", errno, strerror(errno));
}
else if (Data == 0)
{
// timeout
printf("Poll timeout\n");
continue;
}
// Receive DCP UDP
if (FDesc[INTERFACE_UDP_DCP].revents & POLL_ERROR)
{
printf("Poll error on UDP (revents 0x%02x)\n",
FDesc[INTERFACE_UDP_DCP].revents);
}
if (FDesc[INTERFACE_UDP_DCP].revents & POLL_INPUT)
{
int Res = rxDCPUDPData(FDesc[INTERFACE_UDP_DCP].fd);
if(Res!=0)
{
}
}
// Receive LTE UDP
if (FDesc[INTERFACE_UDP_LTE].revents & POLL_ERROR)
{
printf("Poll error on UDP (revents 0x%02x)\n",
FDesc[INTERFACE_UDP_LTE].revents);
}
if (FDesc[INTERFACE_UDP_LTE].revents & POLL_INPUT)
{
int Res = rxLteUDPData(FDesc[INTERFACE_UDP_LTE].fd);
}
}
if(FDesc[INTERFACE_UDP_LTE].fd) close(FDesc[INTERFACE_UDP_LTE].fd);
if(FDesc[INTERFACE_UDP_DCP].fd) close(FDesc[INTERFACE_UDP_DCP].fd);
return 0;
}
自由互联热门推荐:PDF电子发票识别软件,一键识别电子发票并导入到Excel中!10大顶级数据挖掘软件!人工智能的十大作用!
