Linux poll

Linux poll


poll提供的功能与select类似,不过在处理流设备时,它能够提供额外的信息。

1、函数原型
  #include <poll.h>
  int poll(struct pollfd fd[], nfds_t nfds, int timeout);
2、函数参数:
(1)fd:一个结构数组,struct pollfd结构如下:
struct pollfd
{
    int fd;              //文件描述符
    short events;    //请求的事件
    short revents;   //返回的事件
};
  events和revents是通过对代表各种事件的标志进行逻辑或运算构建而成的。events包括要监视的事件,poll用已经发生的事件填充revents。poll函数通过在revents中设置标志肌肤POLLHUP、POLLERR和POLLNVAL来反映相关条件的存在。不需要在events中对于这些标志符相关的比特位进行设置。如果fd小于0, 则events字段被忽略,而revents被置为0.标准中没有说明如何处理文件结束。文件结束可以通过revents的标识符POLLHUN或返回0字节的常规读操作来传达。即使POLLIN或POLLRDNORM指出还有数据要读,POLLHUP也可能会被设置。因此,应该在错误检验之前处理正常的读操作。
poll函数的事件标志符值
常量 说明
POLLIN 普通或优先级带数据可读
POLLRDNORM 普通数据可读
POLLRDBAND 优先级带数据可读
POLLPRI 高优先级数据可读
POLLOUT 普通数据可写
POLLWRNORM 普通数据可写
POLLWRBAND 优先级带数据可写
POLLERR 发生错误
POLLHUP 发生挂起
POLLNVAL 描述字不是一个打开的文件
  注意:后三个只能作为描述字的返回结果存储在revents中,而不能作为测试条件用于events中。
(2)第二个参数nfds:要监视的描述符的数目。

(3)最后一个参数timeout:是一个用毫秒表示的时间,是指定poll在返回前没有接收事件时应该等待的时间。如果  它的值为-1,poll就永远都不会超时。如果整数值为32个比特,那么最大的超时周期大约是30分钟。 INFTIM:永远等待;0:立即返回,不阻塞进程;>0:等待指定毫秒数。

#ifndef _POLL_H_
#define _POLL_H_

#include "wrap.h"
#include "client_list.h"
#include "server_queue.h"

#define SERVER_PORT     6780
#define MAXLINE         100
#define OPEN_MAX        65535
#define TCP_FRAME_SIZE  1200

typedef struct
{
  int sockfd;  // server socket
  int port;    // server port
  struct sockaddr_in addr; // server addr
  int maxi;  // poll max
  struct pollfd event_list[OPEN_MAX]; // poll all event 

  server_queue_t send_queue; // server send data queue to client
  server_queue_t recv_queue; // server recv data queue from client

  pthread_t send_thread;
  pthread_t recv_thread;

  client_t *client;  // client list -- save all client info
} server_t;

/* recv and send queue frame */
typedef struct
{
  int sockfd;  // client socket
  uint16_t length;
  char data[TCP_FRAME_SIZE];
} __packed tcp_frame_t;

//==========================================================
server_t *SocketInit(void);

#endif /* _POLL_H_ */
#include "poll.h"
#include "debug.h"

static server_t *socket_init(void)
{
  int opt = 1, i;
  server_t *current;

  current = (server_t *)malloc(sizeof(server_t));

  current->port = SERVER_PORT;
  current->sockfd = Socket(AF_INET, SOCK_STREAM, 0);
  // SOL_SOCKET: port can same, ip not
  Setsockopt(current->sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
  current->addr.sin_family = AF_INET;
  current->addr.sin_port = htons(current->port);
  current->addr.sin_addr.s_addr = INADDR_ANY;

  Bind(current->sockfd, (struct sockaddr *)¤t->addr, sizeof(current->addr));
  Listen(current->sockfd, MAXLINE);

  current->event_list[0].fd = current->sockfd;
  current->event_list[0].events = POLLIN;
  for(i = 1; i < OPEN_MAX; ++i)
  {
    current->event_list[i].fd = -1;
  }
  current->maxi = current->sockfd;

  ServerQueueInit(&current->send_queue, TCP_FRAME_SIZE);
  ServerQueueInit(&current->recv_queue, TCP_FRAME_SIZE);

  return current;
}

static void socket_accept(server_t *arg)
{
  server_t *current = arg;
  struct sockaddr_in addr;
  int len = sizeof(struct sockaddr_in), i;
  int new_fd = Accept(current->sockfd, (struct sockaddr *)&addr, &len);
  debug("new connection client_fd ( %d ) %s: %d\n", new_fd, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));

  for(i = 0; i < OPEN_MAX; ++i)
  {
    if(current->event_list[i].fd < 0)
    {
      // add new_fd to event_list 
      current->event_list[i].fd = new_fd;
      current->event_list[i].events = POLLIN;
      break;
    }
  }
  if(OPEN_MAX == i)
  {
    printf("too many connects\n");
    Close(new_fd);
    return;
  }

  if(i > current->maxi)
  {
    current->maxi = i;
  }
  /* add client node */
  client_t *node = (client_t *)malloc(sizeof(client_t));
  node->sockfd = new_fd;
  memcpy(&node->addr, &addr, sizeof(struct sockaddr_in));
  ClientAdd(node);
}

static void socket_recv(server_t *arg, int ret)
{
  server_t *current = arg;
  int i, sockfd, length = 0;
  tcp_frame_t write;

  for(i = 1; i <= current->maxi; ++i)
  {
    if((sockfd = current->event_list[i].fd) < 0)
    {
      continue;
    }
    if(current->event_list[i].revents & (POLLIN | POLLERR))
    {
      length = recv(sockfd, write.data, TCP_FRAME_SIZE, 0);
      if(0 == length)
      {
        /* delete client node, close connect socket */
        debug("client[%d] close\n", sockfd);
        ClientDel(sockfd);
        Close(sockfd);
        continue;
      }
      else if(length > 0)
      {
        write.sockfd = sockfd;
        write.length = length;
        server_debug(write.data, write.length);
        // add data to recv_queue, pop in other, 
        if(ServerQueueWrite(&current->recv_queue, (uint8_t *)&write, sizeof(tcp_frame_t)) == 0)
        {
          debug("push failure...queue full...\n");
        }
      }
      if(--ret <= 0)
      {
        break;
      }
    }
  }
}

static void *server_recv_thread(void *arg)
{
  server_t *current = (server_t *)arg;

  while(1)
  {
    int timeout = 3000;
    int ret = Poll(current->event_list, current->maxi, timeout);

    if(current->event_list[0].revents & POLLIN)
    {
      socket_accept(current); // a new connect come
    }
    if(--ret < 0)
    {
      continue;
    }
    socket_recv(current, ret); // a exsit connect send data to us
  }

  Close(current->sockfd);

  return NULL;
}

static void *server_send_thread(void *arg)
{
  server_t *current = (server_t *)arg;
  tcp_frame_t *read = NULL;

  while(1)
  {
    //read = (tcp_frame_t*)ServerQueueRead(&current->send_queue, sizeof(tcp_frame_t));
    if(read != NULL)
    {
      //server_debug(read->data, read->length);
    }

    usleep(100);
  }

  return NULL;
}

server_t * SocketInit(void)
{
  server_t *current = socket_init();
  debug("create thread...\r\n");
  pthread_create(&current->send_thread, NULL, server_send_thread, current);
  pthread_create(&currentt->recv_thread, NULL, server_recv_thread, current);

  return current;
}



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值