慎用select

本文探讨了在网络编程中使用select进行连接状态检查时遇到的问题,特别是当句柄数超过1024时易崩溃的情况。通过对比select、poll及epoll,介绍了如何在RabbitMQ中实现更稳定的非阻塞性连接检查。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://blog.youkuaiyun.com/stpeace/article/details/73718836

select

    //连接代理服务器
    connect(socket, (sockaddr*)&servAddr, sizeof(sockaddr));

    FD_ZERO(&r);
    FD_SET(socket, &r);
    timeout.tv_sec = 5;
    timeout.tv_usec =0;
    ret = select(0, 0, &r, 0, &timeout);
 

如果进程句柄超过1024,select很容易崩溃

后续:经验教训忘记了,今天碰到使用的一个库作为客户端,连接判断非阻塞时判断连接是否成功遇到了,超过1024会崩溃:

bool CheckConnect(const int nSocketfd)
{
    fd_set rset;
    FD_ZERO(&rset);
    FD_SET(nSocketfd, &rset);
    timeval tval;
    tval.tv_sec = 5;
    tval.tv_usec = 0;
    if (select(nSocketfd + 1, NULL, &rset, NULL, &tval) <= 0)
    {
        return false;
    }
    if (FD_ISSET(nSocketfd, &rset))
    {
        int error = -1;
        socklen_t len = sizeof(int);
        if (getsockopt(nSocketfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
        {
            LOG_ERROR("errno: " << errno << " " << strerror(errno));
            return false;
        }
        if (error)
        {
            errno = error;
            LOG_ERROR("errno: " << errno << " " << strerror(errno));
            return false;
        }
    }
    

需要将select改成poll或epoll

下面是rabittmq里面的做法:

  if (0 == connect(sockfd, addr->ai_addr, addr->ai_addrlen)) {
    return sockfd;
  }

  if (EINPROGRESS != errno) {
    last_error = AMQP_STATUS_SOCKET_ERROR;
    goto err;
  }

  last_error = amqp_poll(sockfd, AMQP_SF_POLLOUT, deadline);
  if (AMQP_STATUS_OK != last_error) {
    goto err;
  }

  {
    int result;
    socklen_t result_len = sizeof(result);

    if (-1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &result, &result_len) ||
        result != 0) {
      last_error = AMQP_STATUS_SOCKET_ERROR;
      goto err;
    }
  }

int amqp_poll(int fd, int event, amqp_time_t deadline) {
#ifdef HAVE_POLL
  struct pollfd pfd;
  int res;
  int timeout_ms;

  /* Function should only ever be called with one of these two */
  assert(event == AMQP_SF_POLLIN || event == AMQP_SF_POLLOUT);

start_poll:
  pfd.fd = fd;
  switch (event) {
    case AMQP_SF_POLLIN:
      pfd.events = POLLIN;
      break;
    case AMQP_SF_POLLOUT:
      pfd.events = POLLOUT;
      break;
  }

  timeout_ms = amqp_time_ms_until(deadline);
  if (-1 > timeout_ms) {
    return timeout_ms;
  }

  res = poll(&pfd, 1, timeout_ms);

  if (0 < res) {
    /* TODO: optimize this a bit by returning the AMQP_STATUS_SOCKET_ERROR or
     * equivalent when pdf.revent is POLLHUP or POLLERR, so an extra syscall
     * doesn't need to be made. */
    return AMQP_STATUS_OK;
  } else if (0 == res) {
    return AMQP_STATUS_TIMEOUT;
  } else {
    switch (amqp_os_socket_error()) {
      case EINTR:
        goto start_poll;
      default:
        return AMQP_STATUS_SOCKET_ERROR;
    }
  }
  return AMQP_STATUS_OK;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值