Results 1 to 8 of 8

Thread: Bytes are lost when sending data from C socket to QTcpSocket

  1. #1
    Join Date
    Jan 2011
    Location
    Cape Town, South Africa
    Posts
    4
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Bytes are lost when sending data from C socket to QTcpSocket

    Hi.

    I'm developing a client/server architecture which opens files on a client machine, sends them to a server which does some number crunching and returns a new data type back, 1 for each file received, which is then written to file by the client. I've been struggling with bytes disappearing on the return connection (separate socket to the sending connection).

    All components are currently on a Linux x86_64 platform.

    I'm not an expert on network programming by any length so I've revise this design many times but I've been unable to iron out the problem. The data structure being sent back (called ARD) is similar to a BMP image. It consists of a fixed size header which contains a bunch of info about the data including dimensions of a matrix of 32 bit floats. The matrix is then follow by a string which is for general commenting purposes. The offset and length of the string are stored in the header.

    The socket on the server side is a normal C type socket (sys/socket.h). The server is not a Qt app, its normal C++ command line. The client side is a Qt GUI app so I'm using QTcpSocket which belongs to a non-GUI thread.

    Currently the behavior is quite random. I can successfully get and random number of files back, up to a maximum of about 30 consecutively when things are going well. But at some point I will see corruption of the incoming header and the process comes to a holt as I need to dynamically assign space for the matrix which will now be some random number. This suggests to me that bytes are going missing in the stream which shouldn't really happen in a properly implemented TCP connection.

    The sending function of the server is as follows:

    Qt Code:
    1. int& operator<<(int& sock, Ard& ard)
    2. {
    3. //Set socket fd to blocking mode (Sockets from Qt API are non-blocking by default)
    4. int i = fcntl(sock, F_GETFL);
    5. i = ( i & ~O_NONBLOCK );
    6. fcntl ( sock, F_SETFL,i );
    7.  
    8. ard.updateSizes(); // corrects comment length and offset as well as file size variables
    9.  
    10. unsigned int writeTotal = 0;
    11. char header[Ard::HEADER_SIZE];
    12.  
    13. int bytesWritten;
    14.  
    15. //serialise header
    16. memcpy(header, ard.m_fileType, 4);
    17. memcpy(header + 4, &ard.m_ardType, 1);
    18. memcpy(header + 5, &ard.m_zTime, 8);
    19. memcpy(header + 13, &ard.m_fc, 4);
    20. memcpy(header + 17, &ard.m_fs, 4);
    21. memcpy(header + 21, &ard.m_bw, 4);
    22. memcpy(header + 25, &ard.m_minAmp, 4);
    23. memcpy(header + 29, &ard.m_maxAmp, 4);
    24. memcpy(header + 33, &ard.m_rangeRes, 4);
    25. memcpy(header + 37, &ard.m_dopplerRes, 4);
    26. memcpy(header + 41, &ard.m_xDim, 4);
    27. memcpy(header + 45, &ard.m_yDim, 4);
    28. memcpy(header + 49, &ard.m_txRxDist, 4);
    29. memcpy(header + 53, &ard.m_cOffset, 8);
    30. memcpy(header + 61, &ard.m_cLength, 4);
    31. memcpy(header + 65, &ard.m_fileSize, 8);
    32.  
    33. char *ptr = header;
    34. int bytesLeft = Ard::HEADER_SIZE;
    35.  
    36. while (bytesLeft)
    37. {
    38. bytesWritten = send(sock, ptr, bytesLeft, 0);
    39. ptr += bytesWritten;
    40. writeTotal += bytesWritten;
    41. bytesLeft -= bytesWritten;
    42.  
    43. if(bytesWritten == -1)
    44. cout << "Ard::operator<<(): Error: can't write to socket' " << endl;
    45. }
    46.  
    47. cout << "Ard::operator<<(): After header writeTotal = " << writeTotal << endl;
    48.  
    49. for(unsigned int x = 0; x < ard.m_xDim; x++)
    50. {
    51. bytesLeft = ard.m_yDim * sizeof(float);
    52. ptr = (char*)ard.m_data[x];
    53. while(bytesLeft)
    54. {
    55. bytesWritten = send (sock, ptr, bytesLeft, 0);
    56. bytesLeft -= bytesWritten;
    57. writeTotal += bytesWritten;
    58. ptr += bytesWritten;
    59.  
    60. if(bytesWritten == -1)
    61. cout << "Ard::operator<<(): Error: can't write to socket' " << endl;
    62. }
    63. }
    64.  
    65. cout << "Ard::operator<<(): After data block writeTotal = " << writeTotal << endl;
    66.  
    67. bytesLeft = ard.m_cLength;
    68. char comment[ard.m_cLength];
    69. strncpy (comment, ard.m_comment.c_str(), ard.m_cLength);
    70. ptr = comment;
    71.  
    72. while(bytesLeft)
    73. {
    74. bytesWritten = send (sock, ptr, bytesLeft, 0);
    75. bytesLeft -= bytesWritten;
    76. writeTotal += bytesWritten;
    77. ptr += bytesWritten;
    78.  
    79. if(bytesWritten == -1)
    80. cout << "Ard::operator<<(): Error: can't write to socket' " << endl;
    81. }
    82.  
    83. cout << "Ard::operator<<(): At end of ARD writing writeTotal = " << writeTotal << endl;
    84. return sock;
    85. }
    To copy to clipboard, switch view to plain text mode 

    and the receive code on the client side

    Qt Code:
    1. void QArd::readData(QTcpSocket& sock)
    2. {
    3. int bytesRead;
    4. int bytesLeft;
    5. char* ptr;
    6.  
    7. if(!m_headerRead)
    8. {
    9. if(sock.bytesAvailable() < HEADER_SIZE) //wait for all header data to be available
    10. {
    11. qDebug() << "----socket receving function returning at header";
    12. return;
    13. }
    14.  
    15. bytesLeft = HEADER_SIZE;
    16. char header[HEADER_SIZE];
    17. ptr = header;
    18.  
    19. while (bytesLeft)
    20. {
    21. bytesRead = sock.read(ptr, bytesLeft);
    22. ptr += bytesRead;
    23. m_readTotal += bytesRead;
    24. bytesLeft -= bytesRead;
    25. }
    26.  
    27. //deserialise header
    28. memcpy(m_fileType, header, 4);
    29. memcpy(&m_ardType, header + 4, 1);
    30. memcpy(&m_zTime, header + 5, 8);
    31. memcpy(&m_fc, header + 13, 4);
    32. memcpy(&m_fs, header + 17, 4);
    33. memcpy(&m_bw, header + 21, 4);
    34. memcpy(&m_minAmp, header + 25, 4);
    35. memcpy(&m_maxAmp, header + 29, 4);
    36. memcpy(&m_rangeRes, header + 33, 4);
    37. memcpy(&m_dopplerRes, header + 37, 4);
    38. memcpy(&m_xDim, header + 41, 4);
    39. memcpy(&m_yDim, header + 45, 4);
    40. memcpy(&m_txRxDist, header + 49, 4);
    41. memcpy(&m_cOffset, header + 53, 8);
    42. memcpy(&m_cLength, header + 61, 4);
    43. memcpy(&m_fileSize, header + 65, 8);
    44.  
    45. qDebug() << getInfoString().c_str();
    46.  
    47. qDebug() << "QArd:: read After header readTotal = " << m_readTotal;
    48.  
    49. allocateMatrix();
    50.  
    51.  
    52. m_headerRead = true;
    53. }
    54.  
    55.  
    56.  
    57. while(m_rangeBin < m_xDim)
    58. {
    59. if((unsigned int)sock.bytesAvailable() < sizeof(float) * m_yDim)
    60. {
    61. qDebug() << "----socket receving function returning at data block";
    62. return;
    63. }
    64.  
    65. bytesLeft = m_yDim * sizeof(float);
    66. ptr = (char*)m_data[m_rangeBin];
    67.  
    68. while(bytesLeft)
    69. {
    70. bytesRead = sock.read(ptr, bytesLeft);
    71. m_readTotal += bytesRead;
    72. ptr += bytesRead;
    73. bytesLeft -= bytesRead;
    74. }
    75.  
    76. m_rangeBin++;
    77. }
    78.  
    79. qDebug() << "QArd:: readData() After data block readTotal = " << m_readTotal;
    80.  
    81. if(sock.bytesAvailable() < m_cLength)
    82. {
    83. qDebug() << "----socket receving function returning at comment";
    84. return;
    85. }
    86.  
    87. char comment[m_cLength];
    88. ptr = comment;
    89. bytesLeft = m_cLength;
    90.  
    91. while(bytesLeft)
    92. {
    93. bytesRead = sock.read(ptr, bytesLeft);
    94. m_readTotal += bytesRead;
    95. ptr += bytesRead;
    96. bytesLeft -= bytesRead;
    97. }
    98.  
    99. qDebug() << "COMMENT = " << comment;
    100.  
    101. m_comment = comment;
    102.  
    103.  
    104. qDebug() << m_comment.c_str();
    105. qDebug() << "QArd:: readData() After ARD read finished readTotal = " << m_readTotal;
    106.  
    107. //reset parameters to start reading new plot:
    108. m_rangeBin = 0;
    109. m_headerRead = false;
    110. m_readTotal = 0;
    111.  
    112. //send signal to say reading is complete
    113. readingComplete();
    114. }
    To copy to clipboard, switch view to plain text mode 

    This function is called from another function which is connected to the readyRead() of the socket.

    There is no extra control protocol between sends (which may be bad?) But my understanding is that it shouldn't be necessary except for some sort of network failure. That's not critical for the use case of the system though. The client should receive a known size header then from the header wait for a specified number of bytes of data and then a specified number of bytes for the comment string then wait for the next header. This way it will be easy to allow multiple clients to connect to the system at any point and start receiving the ARD data as well which out a complex sync with each client.

    If anyone can offer any comments suggestions or point out bad design it would be great appreciated, I'm tearing my hair out over this. Also if there could be potential problems elsewhere I'll put up more of the program(s) but I've omitted them for now, they're quite big.

    I am saving the ARD file to disk from the server just before its sent back to the client and I can confirm that the data is correct at that point. I do know that strictly the data should be converted to "network endianess" but thats more a of a cross platform problem. I do most of the testing on between client and server on the same PC. I've also tested it extensively across a network with the same results.

    Kind regards.

  2. #2
    Join Date
    Sep 2011
    Location
    Xi'an China
    Posts
    1
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Bytes are lost when sending data from C socket to QTcpSocket

    Sorry to interrupt you,I am a newcomer in here.I want to ask a question,but I don't know how to do it,could you tell me?Thank you very much!!!

  3. #3
    Join Date
    Jan 2011
    Location
    Cape Town, South Africa
    Posts
    4
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Bytes are lost when sending data from C socket to QTcpSocket

    Click forum in the top bar. Select the category your question applies to. (Probably Qt programming) Then click new thread and fill out the section similar to the way you replied to this thread.

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

    Default Re: Bytes are lost when sending data from C socket to QTcpSocket

    First of all check that your socket is created in a proper thread. Then I suggest to pass sockets as pointers and not references. Then I suggest to not copy data you read directly into structures because of byte order issues. And finally I suggest to simplify your spaghetti code into several functions. Then if the problem persists, it should be easier to track it.
    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.


  5. #5
    Join Date
    Jan 2011
    Location
    Cape Town, South Africa
    Posts
    4
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Bytes are lost when sending data from C socket to QTcpSocket

    Ok thanks.

    When you not don't copy data directly into structures should it go to a QByteArray first then and shift out of it?

    Then regarding the thread.

    I have inherited from QThread:

    Qt Code:
    1. #include "ardThread.h"
    2. #include <QDebug>
    3.  
    4. ArdThread::ArdThread(QObject *parent) : QThread(parent)
    5. {
    6. }
    7.  
    8. ArdThread::~ArdThread()
    9. {
    10. qDebug() << "ARD Thread destructor (" << thread() << ")";
    11. wait();
    12. }
    13.  
    14. void ArdThread::run()
    15. {
    16. qDebug() << "ARD Thread started (" << thread() << ")";
    17.  
    18. exec();
    19. }
    To copy to clipboard, switch view to plain text mode 

    Then I have a class ArdHandler which has the QTcpSocket as a member (which is connected to the server from ArdHandler's constructor).
    ArdHandler has a readyRead() connected to the member socket's readyRead() (connect also made in the constructor).
    The QArd::readData() I posted previously is then called from ArdHandler::readReady()/

    Then in MainWindow:
    Qt Code:
    1. m_ardThread = new ArdThread();
    2. m_ardHandler = new ArdHandler();
    3.  
    4. //connect signals/slots MainWindow to ArdHandler
    5.  
    6. m_ardHandler->moveToThread(m_ardThread);
    7. m_ardThread->start();
    To copy to clipboard, switch view to plain text mode 

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

    Default Re: Bytes are lost when sending data from C socket to QTcpSocket

    Quote Originally Posted by craigt View Post
    When you not don't copy data directly into structures should it go to a QByteArray first then and shift out of it?
    You can do whatever you want as long as you make sure that a little-endian machine can read data sent by a big-endian machine and vice versa. And that different data alignment/structure packing on different platforms doesn't influence the data sent over the wire.

    Then I have a class ArdHandler which has the QTcpSocket as a member (which is connected to the server from ArdHandler's constructor).
    If ArdHandler is not set explicitly as a parent of the socket then your code is incorrect, the socket will remain in the thread where you constructed ArdHandler and you will be losing data from the socket. Just be aware that if you do set it as a parent, you will have to properly delete the object, otherwise you'll have double deletion problems. I think it is safer to not make the socket a member variable of the handler. If you want, then just keep a pointer to the socket as a member variable of the handler.
    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.


  7. #7
    Join Date
    Jan 2011
    Location
    Cape Town, South Africa
    Posts
    4
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Bytes are lost when sending data from C socket to QTcpSocket

    Ok fantastic!

    Using setParent of the socket in ArdHandler seems to have sorted it out. I've run it a couple time for hundreds of cycles with no missing data. It makes sense actually. The socket is initialised from the handler's constructor which is in turn called from MainWindow so its essentially MainWindow code. I didn't even stop to consider that.

    I think it is safer to not make the socket a member variable of the handler. If you want, then just keep a pointer to the socket as a member variable of the handler.
    So would I then declare/intialise the socket in MainWindow, also move it to the QThread and provide a pointer to the handler?

    Several times I've seen it recommended that the socket be declared and initialised in the run() of the QThread which will safely make it belong to the thread. It becomes a little hard to get access to it that way though.

    You can do whatever you want as long as you make sure that a little-endian machine can read data sent by a big-endian machine and vice versa. And that different data alignment/structure packing on different platforms doesn't influence the data sent over the wire.
    I am aware of this. I've left it out for now as I'm working on very similar platforms and testing the 2 programs mainly on the same machine. Some the data is coming through correctly so the endianess must be matched. It isn't going to change mid send as far as I understand, its normally fixed to a given platform. I will add this to the code once I get a basic prototype going.

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

    Default Re: Bytes are lost when sending data from C socket to QTcpSocket

    Quote Originally Posted by craigt View Post
    Using setParent of the socket in ArdHandler seems to have sorted it out. I've run it a couple time for hundreds of cycles with no missing data. It makes sense actually. The socket is initialised from the handler's constructor which is in turn called from MainWindow so its essentially MainWindow code. I didn't even stop to consider that.
    It's simpler than that. When you use moveToThread(), the object is moved together will all its children. However since the socket is not a child of the handler, it is kept in the thread that created the ArdHandler object.

    So would I then declare/intialise the socket in MainWindow, also move it to the QThread and provide a pointer to the handler?
    No, you can create the socket in constructor of the handler object and set the handler object as parent of the socket. Then when you move the handler, the socket will move together with it.

    Several times I've seen it recommended that the socket be declared and initialised in the run() of the QThread which will safely make it belong to the thread. It becomes a little hard to get access to it that way though.
    No, you can still a pointer to the socket in the containing object. However in your situation you don't have to subclass QThread at all.


    I am aware of this. I've left it out for now as I'm working on very similar platforms and testing the 2 programs mainly on the same machine. Some the data is coming through correctly so the endianess must be matched.
    If you use the same platform then they will match, however you should think about it already because later you will just forget about it and might run into trouble later.
    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.


Similar Threads

  1. QTcpSocket get disconnected when server is sending huge data
    By KernelCoder in forum Qt Programming
    Replies: 3
    Last Post: 1st April 2011, 08:45
  2. Replies: 8
    Last Post: 18th December 2010, 15:07
  3. Replies: 1
    Last Post: 18th October 2010, 16:07
  4. Events lost in IPC through local socket in Windows
    By yogesh in forum Qt Programming
    Replies: 1
    Last Post: 24th May 2009, 11:38
  5. socket read/write bytes
    By nowire75 in forum Newbie
    Replies: 3
    Last Post: 4th July 2007, 23:12

Tags for this Thread

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
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.