Ускорение неблокирующих Unix Sockets (C ++) - PullRequest
0 голосов
/ 25 июня 2009

Я реализовал простой класс-оболочку сокетов. Включает неблокирующую функцию:

void Socket::set_non_blocking(const bool b) {
    mNonBlocking = b; // class member for reference elsewhere
    int opts = fcntl(m_sock, F_GETFL);
    if(opts < 0) return;
    if(b)
        opts |= O_NONBLOCK;
    else
        opts &= ~O_NONBLOCK;

    fcntl(m_sock, F_SETFL, opts);
}

Класс также содержит простую функцию приема:

int Socket::recv(std::string& s) const {
    char buffer[MAXRECV + 1];
    s = "";
    memset(buffer,0,MAXRECV+1);
    int status = ::recv(m_sock, buffer, MAXRECV,0);

    if(status == -1) {
    if(!mNonBlocking)
        std::cout << "Socket, error receiving data\n";

        return 0;
    } else if (status == 0) {
        return 0;
    } else {
        s = buffer;
        return status;
    }
}

На практике кажется, что при вызове Socket :: recv () происходит задержка ~ 15 мс. Этой задержки можно избежать? Я видел несколько неблокирующих примеров, в которых используется select (), но не понимаю, как это может помочь.

Ответы [ 4 ]

1 голос
/ 25 июня 2009

Зависит от того, как вы используете сокеты. Если у вас есть несколько сокетов, и вы перебираете все из них, проверяя данные, которые могут объяснить задержку.

С неблокирующим recv вы зависите от имеющихся там данных. Если вашему приложению нужно использовать более одного сокета, вам придется постоянно объединять каждый сокет по очереди, чтобы выяснить, есть ли у любого из них доступные данные.

Это плохо для системных ресурсов, поскольку означает, что ваше приложение постоянно работает, даже когда нечего делать.

Вы можете избежать этого с помощью select. Вы в основном настраиваете свои сокеты, добавляете их в группу и выбираете в группе. Когда что-либо происходит с любым из выбранных сокетов, select возвращает, указывая, что произошло и на каком сокете.

Для некоторого кода о том, как использовать select, посмотрите Руководство beej по сетевому программированию

0 голосов
/ 21 июля 2009

Насколько велика ваша MAXRECV? Может случиться так, что вы столкнетесь с ошибкой страницы при увеличении стека. Другие уже упоминали, что обнуление приемного буфера совершенно не нужно. Вы также занимаете выделение памяти и копируете попадание при создании std::string из полученных символьных данных.

0 голосов
/ 25 июня 2009

В дополнение к stefanB я вижу, что вы каждый раз обнуляете свой буфер. Зачем беспокоиться? recv возвращает количество прочитанных байтов. Просто обнулите один байт после (буфер [status + 1] = NULL)

0 голосов
/ 25 июня 2009

select позволит вам указать время ожидания и может проверить, готов ли сокет для чтения. Таким образом, вы можете использовать что-то меньше, чем 15 мс. Кстати, вам нужно быть осторожным с тем кодом, который у вас есть, если данные на проводе могут содержать встроенные NUL, которые не будут содержать все прочитанные данные. Вы должны использовать что-то вроде s.assign(buffer, status);.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...