Results 1 to 20 of 21

Thread: QTcpSocket Chat : Mutiple Client using FD_SET and select()

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Join Date
    Sep 2007
    Posts
    13
    Qt products
    Qt4
    Platforms
    Windows
    Thanks
    1
    Thanked 1 Time in 1 Post

    Default QTcpSocket Chat : Mutiple Client using FD_SET and select()

    I was able to send the message using a single client. Now I want to implement for multiple client. How can I do it under Qt using select() method. I prefer this because I have done it using normal socket without Qt.

    My application is using TCP socket which have client and server. I want to make a simple chat program which can 1 client send to server and server send to all the rest of client connected.

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,373
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    3
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QTcpSocket Chat : Mutiple Client using FD_SET and select()

    But is there a specific question here somewhere? And what does it have to do with Qt? I understand you are using BSD sockets, right?

  3. #3
    Join Date
    Sep 2007
    Posts
    13
    Qt products
    Qt4
    Platforms
    Windows
    Thanks
    1
    Thanked 1 Time in 1 Post

    Default Re: QTcpSocket Chat : Mutiple Client using FD_SET and select()

    I using QTcpSocket. From the SimpleChat Example posted here, it is using QHash to store the client list. Is it possible to use select() method to do it?

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,373
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    3
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QTcpSocket Chat : Mutiple Client using FD_SET and select()

    If you use Qt sockets, don't use select(). It just won't work. Use signals and slots instead.

  5. The following user says thank you to wysota for this useful post:

    cooler123 (21st September 2007)

  6. #5
    Join Date
    Sep 2007
    Posts
    13
    Qt products
    Qt4
    Platforms
    Windows
    Thanks
    1
    Thanked 1 Time in 1 Post

    Default Re: QTcpSocket Chat : Mutiple Client using FD_SET and select()

    OIC. Thanks for the reply.

  7. #6
    Join Date
    Nov 2010
    Posts
    122
    Qt products
    Qt4 Qt/Embedded
    Platforms
    Unix/X11 Windows
    Thanks
    62
    Thanked 3 Times in 3 Posts

    Cool Re: QTcpSocket Chat : Mutiple Client using FD_SET and select()

    I wanted to follow up on thread in this year of 2012 and see if things might have changed, or if there is additional thoughts and wisdom based on
    changes that have been made to Qt since the original article posting.

    I have to manage up to 10 TCP-IP connections and singular UDP socket
    as the highest priority task in my application. I have used the Linux
    'select" API in the past successfully, and wanted to leverage this
    method for handling 10 Tcp Sockets in either separate threads, or
    perhaps a singular thread managing all of them.

    My current application implementation avoids using the default Qt
    event loop in secondary threads to more clearly control running
    thread activity (avoid duty cycle of event loop).

    The following code sample illustrates my first implementation using
    a QUdpSocket and a collection of QTcpSockets.

    It in general works, I can send and receive data with UDP recipients and
    TCP-IP servers.

    Now here is the downside. The Linux statement will exit in a few
    microseconds each time on the file descriptor corresponding to the
    TCP-IP socket. This will occur even when no data is available.
    As a result, my desire for this thread to pend until TCP-IP data
    becomes available does not happen, and this leads to great
    inefficiencies in the design.

    So the question I have is, is the QTcpSocket class fundamentally
    structured so that it can not be simple modified to handle this
    one issue? Is there a small tweak that can be made (say a
    subclass or socket option) that would be a quick fix to this
    singular issue.

    Assuming I replace the QTcpSocket class with standard Linux sockets,
    what value added features/performance of QTcpSocket would be badly missed
    (e.g.buffering).

    Wsoyata the sage, what do you think?

    Qt Code:
    1. timeval tvNow, tvTimeout, tvNextEpoch;
    2. tvNow = TimeUtils::getTime();
    3. tvTimeout = tvNow;
    4. tvNextEpoch = timevalNextEpoch(tvNow, m_epochMicroseconds);
    5.  
    6. quint32 processingDelayAdjustment = 0;
    7. fd_set readS, exS;
    8. int maxFd = 0;
    9.  
    10. #define SELECT_TIMING_TEST
    11. #ifdef SELECT_TIMING_TEST
    12. timeval tvStart, tvElapsed;
    13. tvStart = tvNow;
    14. tvElapsed = tvNow;
    15. #endif
    16.  
    17. // Task loop
    18. while (!m_stopped)
    19. {
    20. // Setup for ::select() statement
    21. FD_ZERO(&readS);
    22. FD_ZERO(&exS);
    23.  
    24. maxFd = 0;
    25. maxFd = qMax(maxFd, udpSocketDescriptor);
    26.  
    27. // Add UDP socket to read file descriptor set
    28. FD_SET(udpSocketDescriptor, &readS);
    29. FD_SET(udpSocketDescriptor, &exS);
    30.  
    31. // Iterate through list of active sockets TCP-IP sockets
    32. for (QMap<int, SockInfo *>::iterator it = m_currentSockets.begin(); it != m_currentSockets.end(); ++it)
    33. {
    34. int socket = it.key();
    35.  
    36. // Add TCP socket to read and exception file descriptor sets
    37. FD_SET(socket, &readS);
    38. FD_SET(socket, &exS);
    39.  
    40. maxFd = qMax(maxFd, socket);
    41. }
    42.  
    43. // Update select statement timeout value to the interval to the start of the next epoch
    44. timeoutUpdate(tvTimeout, tvNextEpoch, processingDelayAdjustment);
    45.  
    46. // Count of available file descriptors
    47. int count = 0;
    48.  
    49. // Invoke select if the timeout to the next epoch is non-zero
    50. if (tvTimeout.tv_usec != 0 || tvTimeout.tv_sec != 0)
    51. {
    52. #ifdef SELECT_TIMING_TEST
    53. #define SELECT_TIMING_TEST_LOGLEVEL logDEBUG4
    54. if (FILELog::ReportingLevel() >= SELECT_TIMING_TEST_LOGLEVEL)
    55. {
    56. // Get start time prior to select
    57. TimeUtils::getTime(&tvStart);
    58. msg = QString("Select In: now (%1/%2), timeout (%3/%4), tvNextEpoch (%5/%6)").arg(tvStart.tv_sec).arg(tvStart.tv_usec).arg(tvTimeout.tv_sec).arg(tvTimeout.tv_usec).arg(tvNextEpoch.tv_sec).arg(tvNextEpoch.tv_usec);
    59. FILE_LOG(SELECT_TIMING_TEST_LOGLEVEL) << qPrintable(msg);
    60. }
    61. #endif
    62.  
    63. // Wait for a number of file descriptors to change status or a timeout
    64. count = ::select(maxFd + 1, &readS, NULL, &exS, &tvTimeout);
    65.  
    66. #ifdef SELECT_TIMING_TEST
    67. if (FILELog::ReportingLevel() >= SELECT_TIMING_TEST_LOGLEVEL)
    68. {
    69. // Get system time after select call
    70. tvNow = TimeUtils::getTime();
    71.  
    72. // Display elapsed time and other content
    73. tvElapsed = tvNow - tvStart;
    74. msg = QString("Select Out: now (%1/%2), timeout (%3/%4), tvNextEpoch (%5/%6), elapsed (%7/%8), count %9").
    75. arg(tvNow.tv_sec).arg(tvNow.tv_usec).arg(tvTimeout.tv_sec).arg(tvTimeout.tv_usec).
    76. arg(tvNextEpoch.tv_sec).arg(tvNextEpoch.tv_usec).arg(tvElapsed.tv_sec).arg(tvElapsed.tv_usec).arg(count);
    77. FILE_LOG(SELECT_TIMING_TEST_LOGLEVEL) << qPrintable(msg);
    78. }
    79. #endif
    80. }
    81.  
    82. // Get system time after select call
    83. tvNow = TimeUtils::getTime();
    84.  
    85. // On epoch boundary, perform epoch activities
    86. if (tvNextEpoch <= tvNow)
    87. {
    88. // Update the time of the next epoch (calculate the time of day to the start of the next epoch boundary)
    89. tvNextEpoch = timevalNextEpoch(tvNow, m_epochMicroseconds);
    90.  
    91. // Should be aligned to even multiple of epoch on timeout. Calculate how far off it was to make runtime adjustment for the next pass (routine timeoutUpdate())
    92. processingDelayAdjustment = tvNow.tv_usec % m_epochMicroseconds;
    93.  
    94. if (FILELog::ReportingLevel() >= logDEBUG4)
    95. {
    96. int epochNumber = timevalToEpoch(tvNow.tv_usec, m_epochMicroseconds);
    97.  
    98. msg = QString("TDMA: Epoch %1 at (%2/%3), timeout (%4/%5), delay adjust (%6)").
    99. arg(epochNumber).arg(tvNow.tv_sec).arg(tvNow.tv_usec).arg(tvTimeout.tv_sec).arg(tvTimeout.tv_usec).arg(processingDelayAdjustment);
    100. FILE_LOG(logDEBUG4) << qPrintable(msg);
    101. }
    102.  
    103. onEpoch();
    104.  
    105. } // end Epoch activities
    106.  
    107.  
    108.  
    109. // Exit thread when stopped
    110. if (m_stopped)
    111. {
    112. break;
    113. }
    114.  
    115. // Packets found, process them
    116. if (count > 0)
    117. {
    118.  
    119. // RadioG-LM TA radio queue status messages
    120. if (FD_ISSET(udpSocketDescriptor, &readS))
    121. {
    122. if (FILELog::ReportingLevel() >= logDEBUG4)
    123. {
    124. msg = QString("TDMA: select() exit with count %1: UDP socket read file descriptor %2 set at (%3/%4)").
    125. arg(count).arg(udpSocketDescriptor).arg(tvNow.tv_sec).arg(tvNow.tv_usec);
    126. FILE_LOG(logDEBUG4) << qPrintable(msg);
    127. }
    128.  
    129. static QHostAddress recvFrom;
    130. static QByteArray datagram;
    131.  
    132. // Assemble a full UDP datagram
    133. do
    134. {
    135. datagram.resize(m_udpSocket->pendingDatagramSize());
    136. m_udpSocket->readDatagram(datagram.data(), datagram.size(), &recvFrom);
    137. } while (m_udpSocket->hasPendingDatagrams());
    138.  
    139. // Process contents of UDP datagram
    140. processLinkManagerMessage(datagram, recvFrom);
    141. }
    142.  
    143. // UDP socket exception
    144. if (FD_ISSET(udpSocketDescriptor, &exS))
    145. {
    146. FILE_LOG(logERROR) << "TDMA: select() exception detected for UDP socket: " << udpSocketDescriptor;
    147. }
    148.  
    149. // Check all TCP-IP LM-QM connections in the collection
    150. for (QMap<int, SockInfo *>::iterator it = m_currentSockets.begin(); it != m_currentSockets.end(); ++it)
    151. {
    152. int socket = it.key();
    153.  
    154. // Socket read
    155. if (FD_ISSET(socket, &readS))
    156. {
    157. if (FILELog::ReportingLevel() >= logDEBUG4)
    158. {
    159. msg = QString("TDMA: select() exit with count %1: TCP-IP socket read file descriptor %2 set at (%3/%4)").
    160. arg(count).arg(socket).arg(tvNow.tv_sec).arg(tvNow.tv_usec);
    161. FILE_LOG(logDEBUG4) << qPrintable(msg);
    162. }
    163.  
    164. // QM TCP-IP receive handler
    165. SockInfo *sockInfo = it.value();
    166. if (sockInfo)
    167. {
    168. processSocketMessage(sockInfo);
    169. }
    170. }
    171.  
    172. }
    173.  
    174. } // end count > 1
    175.  
    176. } // end while
    To copy to clipboard, switch view to plain text mode 

  8. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,373
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Thanks
    3
    Thanked 5,019 Times in 4,795 Posts
    Wiki edits
    10

    Default Re: QTcpSocket Chat : Mutiple Client using FD_SET and select()

    Qt uses standard sockets too, so if you're just after calling select manually, you can do that if you really want to, however I don't see how your code would be faster than what Qt does (apart the trick Qt does with adding an extra descriptor to the set).

    As for your problem... try detecting WHAT causes select() to return (EINTR maybe?).
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Qt is a trademark of The Qt Company.