C++套接字从未准备好使用轮询进行写入

C++ socket never ready for write with poll

本文关键字:套接字 未准备 准备好 C++      更新时间:2023-10-16

我正在为Linux上的套接字编写一个C++包装器。我可以将读/写连接到http服务器,我的轮询功能非常适合阅读,但由于某些原因,它不适合写作。我尝试过使用gdb,当fd.events是POLLOUT 时,轮询似乎将fd.revents设置为0

轮询代码:

/**
 *@brief assigns request.reply based on fd.revents
 */
static void translate_request(mizaru::PollRequest &request, pollfd &fd)
{
    assert( (fd.revents & POLLHUP) == 0);
    assert( (fd.revents & POLLERR) == 0);
    assert( (fd.revents & POLLNVAL) == 0);

    switch(fd.revents)
  {
      case (POLLIN | POLLOUT) :
        request.reply = mizaru::POLL_REPLY_RW;
        break;
      case POLLIN :
        request.reply = mizaru::POLL_REPLY_READ;
        break;
      case POLLOUT :
        request.reply = mizaru::POLL_REPLY_WRITE;
      default :
        request.reply = 0;
  }
}
/**
 * @fills in fd.events based on request.request
 * and fd.fd based on request.sock
 */
static void prep_request(mizaru::PollRequest &request, pollfd &fd)
{
    fd.fd = request.sock.get_handle();
    switch(request.request)
  {
    case mizaru::PollType::POLL_READ :
      fd.events = POLLIN;
      break;
    case mizaru::PollType::POLL_WRITE :
      fd.events = POLLOUT;
      break;
    default :
      fd.events = POLLIN | POLLOUT;
  }

}
void mizaru::trans::poll(mizaru::PollRequest &request,const std::chrono::milliseconds& wait_time) noexcept
{
  pollfd fd;
  prep_request(request, fd);
  poll(&fd, 1, wait_time.count());
  translate_request(request, fd);
}

mizaru::PollRequest结构体:

struct PollRequest
{
  PollRequest(PollType request, const SyncSocket &sock) : sock(sock), request(request), reply(POLL_REPLY_FAIL) {}
  const SyncSocket & sock;
  PollType request;
  uint8_t reply;
};

SyncSocket.get_handle()只是返回socket(int,int,int)sys/socket.h 中返回的fd

测试功能:

bool test_poll()
{
    mizaru::IPv4 ip ( "54.225.138.124" );
    mizaru::SyncSocketTCP sock ( ip, 80 ,true);
    mizaru::PollRequest  request{mizaru::PollType::POLL_READ, sock};
    std::chrono::milliseconds time(1000);
    mizaru::poll(request, time);
    if(request.reply == mizaru::POLL_REPLY_READ)
    {
      std::cout << "fail test_poll first read" <<std::endl;
       return false;
    } 
    request.request = mizaru::PollType::POLL_WRITE;
    mizaru::poll(request, time);
    if(request.reply != mizaru::POLL_REPLY_WRITE)
    {
      std::cout << "fail test_poll first write" << std::endl;
      return false;
    }
 std::string toWrite ( "GET / http/1.1nHost: httpbin.orgnn" );
 mizaru::byte_buffer write_buff;
for ( char c : toWrite )
    {
      write_buff.push_back ( c );
    }
  unsigned int r_value = sock.write ( write_buff );
   if (r_value != toWrite.size()) 
   {
      std::cout << "fail test_poll r_value" << std::endl;
      return false;
   }

    request.request = mizaru::PollType::POLL_READ;
    mizaru::poll(request, time);
    if(request.reply != mizaru::POLL_REPLY_READ)
    {
       std::cout << "fail test_poll second read" << std::endl;
        return false;
    }
    request.request = mizaru::PollType::POLL_WRITE;
    mizaru::poll(request, time);
    if(request.reply != mizaru::POLL_REPLY_WRITE)
    {
      std::cout << "fail test_poll second write " << std::endl;
        return false;
    }
    return true;
}

PollType枚举:

enum PollType {POLL_READ, POLL_WRITE, POLL_RW};

POLL_REPLY_*常数:

constexpr uint8_t POLL_REPLY_READ = 0x01;
constexpr uint8_t POLL_REPLY_WRITE = 0x02;
constexpr uint8_t POLL_REPLY_RW = POLL_REPLY_READ | POLL_REPLY_WRITE;
constexpr uint8_t POLL_REPLY_FAIL = 0;

很抱歉,示例代码无法直接编译,我试图将其缩短,由于我得到了一个正确的HTTP200OK回复,您可以假设连接和读/写处理得当。轮询写入时测试失败

translate_request():中

switch(fd.revents)
{
  case (POLLIN | POLLOUT) :
    request.reply = mizaru::POLL_REPLY_RW;
  break;
  case POLLIN :
    request.reply = mizaru::POLL_REPLY_READ;
  break;
  case POLLOUT :
    request.reply = mizaru::POLL_REPLY_WRITE;
  default :
    request.reply = 0;
}

POLLOUTdefault两种情况下,您都缺少一个breakPOLLOUT下降到default,消除了POLLOUT发生的证据。