libev将套接字设置为阻塞而没有超时

时间:2012-12-08 23:53:50

标签: c++ sockets timeout nonblocking libev

Rant:我真的不喜欢boost :: asio,所以我一直在寻找替代方案并遇到了libev。这对我来说似乎很简单,但是做了一些我无法理解的事情。如果在一个帖子中有太多问题,请告诉我。

1)我将侦听套接字设置为NON_BLOCK,我还将每个接受的传入连接设置为NON_BLOCK,但在代码中的某个地方,套接字变为BLOCK。 例如:

bool Server::Start()
{
    // Setup event loop
    loop = ev_default_loop(EVBACKEND_SELECT); //EVFLAG_AUTO ?
    // Create Socket
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    addr_len = sizeof(addr)
    // Set Socket to non blocking
    fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
    if (fcntl(sockfd, F_GETFL) & O_NONBLOCK) std::cout << "Socket is NONBLOCK" << std::endl;
    else std::cout << "Socket is BLOCK" << std::endl;
    if (sockfd < 0) {
        std::cout << "ERROR opening socket" << std::endl;
        return false;
    }
    bzero((char *)&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;
    // Bind port to socket
    if (bind(sockfd,(struct sockaddr*)&addr, sizeof(addr))!=0) {
        std::cout << "bind error" << std::endl;
        return false;
    }
    // Listen
    if (listen(sockfd, 2) < 0) {
        std::cout << "listen error" << std::endl;
        return false;
    }
    // Initialize and start a watcher to accepts client requests
    ev_io_init(&w_accept, accept_cb, sockfd, EV_READ);
    ev_io_start(loop, &w_accept);
    return true;
}

我试图让主循环也不阻止:

void Server::MainLoop()
{
    // Start infinite loop
    while (1) {
        ev_loop(loop, EVLOOP_NONBLOCK);
    }
}

但它似乎没有做出与众不同。请不要将我重定向到文档(互联网上唯一可用的文档来源)我已阅读它。

我为已接受的客户端套接字执行此操作:

void accept_cb(struct ev_loop *loop, struct ev_io *watcher, int revents)
....
c->client_sd = accept(watcher->fd, (struct sockaddr *)&c->client_addr, &c->client_len);
....
ev_io *w_client = (struct ev_io*) malloc (sizeof(struct ev_io));
ev_io_init(w_client, read_cb, c->client_sd, EV_READ);
ev_io_start(loop, w_client);
fcntl(watcher->fd, F_SETFL, fcntl(watcher->fd, F_GETFL) | O_NONBLOCK);

然而,每次执行读取回调时,套接字都会神奇地设置为BLOCK

2)我尝试为套接字设置超时: struct timeval timeout;

timeout.tv_sec = 10;
timeout.tv_usec = 0;

if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
            sizeof(timeout)) < 0)
    error("setsockopt failed\n");

if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,
            sizeof(timeout)) < 0)
    error("setsockopt failed\n");

(摘自:this question) 它根本不起作用。这是因为套接字被重置为BLOCKing模式吗?

3)我见过一个用于libev的C ++包装器。我绝对讨厌我必须使回调静态函数的事实,它为我破坏了一切。然而我见过的所有例子都使用了:

signal.loop.break_loop();

loop.run(0);

,有趣地产生了:

  

错误:'struct ev :: loop_ref'没有名为'break_loop'的成员错误:   'struct ev :: default_loop'没有名为'run'的成员

关于Debian Squeeze。

所以,我要问的是:

  1. 什么,谁,套接字在哪里从NON_BLOCK变为BLOCK?
  2. 如何(如果)可以为套接字设置超时(阻塞或非阻塞)
  3. ev ++有什么问题。为什么这些好人使用我不能使用的包装?
  4. 请记住,我可以使用套接字来读取和发送数据,但是以阻塞的方式,没有超时。此外,由于这是一个服务器,我需要将代码保留在类中,因为我必须为每个连接的客户端保存消息。制作这种静态或非类方法只会破坏它,或者迫使我采取一种非常不同的方法。

    PS:libev的替代品吗?

1 个答案:

答案 0 :(得分:3)

您没有将客户端FD设置为非阻止模式。您正在设置侦听套接字FD。