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) Я попытался установить время ожидания для сокета:
структура timeval таймаут;
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");
(Взято отсюда: этот вопрос)
Это просто не работает. Это из-за того, что розетки сброшены в режим БЛОКИРОВКИ?
3) Я видел оболочку C ++ для libev. Я абсолютно ненавижу тот факт, что я должен делать обратные вызовы статическими функциями, это все разрушает для меня. Все же все примеры, которые я видел, используют:
signal.loop.break_loop();
а также
loop.run(0);
который, как ни странно, производит:
ошибка: структура ev :: loop_ref не имеет члена с именем break_loop ошибка:
Ev struct ev :: default_loop ’не имеет члена с именем« run »
на Debian Squeeze.
Итак, я спрашиваю:
Пожалуйста, помните, что я могу использовать сокеты для чтения и отправки данных, но в режиме блокировки, без таймаутов. Кроме того, поскольку это сервер, мне нужно хранить код в классах, так как я должен сохранять сообщения для каждого подключенного клиента. Создание этого статического или неклассного метода просто разрушает его или заставляет меня придерживаться совершенно другого подхода.
PS: Есть ли альтернативы libev?
Вы не устанавливаете клиентский FD в неблокирующий режим. Вы устанавливаете гнездо для прослушивания FD.
Других решений пока нет …