Linux C - poll示例


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;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM