Qt Socket Notifier - No events received, high cpu load



  • Hi all,

    i'm writing a Qt SIGNAL/SLOT capable class in order to be able to work with raw socket in a Qt application.

    To achieve this, i'm using a QSocketNotifier to monitor socket incoming data event in a S/S way.

    Now the problem: entering the event loop, causes the process CPU utilization to raise to 100%, locking every event.and the QSocketNotifier signal activated(int socket) is never triggered. Removing the QSocketNotifier declaration, the loop works normally.

    Here i've made a reduced compilable code set to better show the unwanted behavior:
    (The program create a ICMP raw socket: to create ICMP traffic, just ping yourself at 127.0.0.1)

    NOTE: raw socket requires root privileges: run the test program in root mode.

    [CODE]
    /*

    • File: main.cpp
    • Author: root
    • Created on 29 agosto 2011, 17.28
      */

    #include <QCoreApplication>
    #include <QSocketNotifier>

    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <fcntl.h>
    #include <errno.h>

    int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if(sock == -1){
        qDebug("Socket Creation Failure");
        return -10;
    }
    //ALSO TRYED IN NON BLOCKING MODE; SAME RESULTS
    //fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
    
    
    //THESE LINES ALLOW THE PROGRAM TO STOP FOR THE FIRST AVAILABLE ICMP PACKET
    //COMMENT THEM IF YOU WISH NOT TO WAIT FOR THE FIRST PCK OUTSIDE EVENT LOOP.
    unsigned char buff[1024];
    int length = recv(sock, buff, 1024, 0);
    qDebug(("Received: " + QString::number(length)).toStdString().c_str());
    
    //THE GUILTY LINE: COMMENT THIS TO SEE A NORMAL CALM EMPTY EVENT LOOP
    QSocketNotifier notifier(sock, QSocketNotifier::Read);
    
    return app.exec&#40;&#41;;
    

    }

    [/CODE]

    I've monitored the process with strace: that's the main loop start point
    [CODE]
    pipe2([5, 6], O_NONBLOCK|O_CLOEXEC) = 0
    rt_sigaction(SIGCHLD, {0xb6acbf20, [], SA_NOCLDSTOP}, {SIG_DFL, [], 0}, 8) = 0
    socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 7
    clock_gettime(CLOCK_MONOTONIC, {16395, 460509112}) = 0
    poll([{fd=3, events=POLLIN}, {fd=7, events=POLLIN}], 2, 0) = 0 (Timeout)
    clock_gettime(CLOCK_MONOTONIC, {16395, 460708575}) = 0
    poll([{fd=3, events=POLLIN}, {fd=7, events=POLLIN}], 2, -1) = 1 ([{fd=7, revents=POLLIN}])
    clock_gettime(CLOCK_MONOTONIC, {16395, 752324322}) = 0
    poll([{fd=3, events=POLLIN}, {fd=7, events=POLLIN}], 2, -1) = 1 ([{fd=7, revents=POLLIN}])
    ...
    [/CODE]

    Then the program starts to flood the last two lines.
    I've tried to change the family, type and protocol during the socket creation in:
    [CODE]
    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    [/CODE]
    and this is the result:
    [CODE]
    pipe2([5, 6], O_NONBLOCK|O_CLOEXEC) = 0
    rt_sigaction(SIGCHLD, {0xb6aaff20, [], SA_NOCLDSTOP}, {SIG_DFL, [], 0}, 8) = 0
    socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP) = 7
    clock_gettime(CLOCK_MONOTONIC, {16759, 34270708}) = 0
    poll([{fd=3, events=POLLIN}, {fd=7, events=POLLIN}], 2, 0) = 0 (Timeout)
    clock_gettime(CLOCK_MONOTONIC, {16759, 34399931}) = 0
    poll([{fd=3, events=POLLIN}, {fd=7, events=POLLIN}], 2, -1
    [/CODE]
    In this case, the programs start waiting for incoming events, without producing anymore output and without consuming any CPU.
    You can see there are no significant changes in the call sequence

    NOTE In my program i've connected the QSocketNotifier::activated signal to a slot, wich is never called. This is not shown in the upper code.

    Hope someone will find the trick!
    Thanks,
    Regards,

    Gianluca



  • @
    /*

    • File: main.cpp
    • Author: root
    • Created on 29 agosto 2011, 17.28
      */

    #include <QCoreApplication>
    #include <QSocketNotifier>
    #include <QtDebug>

    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <fcntl.h>
    #include <errno.h>

    class RawSocketReader : public QObject
    {
    Q_OBJECT

    public slots:
    void doSomething(int socket)
    {
    unsigned char buff[1024];
    int length;
    while ((length = recv(socket, buff, 1024, 0)) >= 0) {
    qDebug() << "Received" << length << "bytes";
    }
    }
    };

    #include "main.moc"

    int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    
    if(sock == -1){
        qDebug("Socket Creation Failure");
        return -10;
    }
       
    fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK); 
    
    QSocketNotifier notifier(sock, QSocketNotifier::Read);
    RawSocketReader reader;
    QObject::connect(& notifier, SIGNAL(activated(int)), &reader, SLOT(doSomething(int)));
     
    return app.exec(&#41;;
    

    }
    @

    This is working as expected.

    Set the sockets as nonblocking to use them inside a select/poll-based event loop

    Always read everything when the socket notifier fires



  • That's solved!

    I didn't know i have to read everything every time in order to avoid infinite signal emission.

    Thanks a lot.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.