views:

74

answers:

2

Hello, I'm trying to connect a very basic twisted "hello world" server with a basic Qt tcp client.

The client uses these Signals:

connect(&socket, SIGNAL(connected()), this, SLOT(startTransfer()));
connect(&socket, SIGNAL(readyRead()), this, SLOT(readServer()));

and then readServer() looks like this:

ui->resultLabel->setText("Reading..");
QDataStream in(&socket);
//in.setVersion(QT_4_0);

if (blockSize == 0) {
    if (socket.bytesAvailable() < (int)sizeof(quint16))
        return;

    in >> blockSize;
}

if (socket.bytesAvailable() < blockSize)
    return;

QString theResult;
in >> theResult;
qDebug() << in;
qDebug() << theResult;
ui->resultLabel->setText(theResult);

The server I'm using for testing purposes is simply an example grabbed off of twisted's docs

from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor

### Protocol Implementation

# This is just about the simplest possible protocol
class Echo(Protocol):
    def dataReceived(self, data):
        """
        As soon as any data is received, write it back.
        """
        self.transport.write(data)


def main():
    f = Factory()
    f.protocol = Echo
    reactor.listenTCP(8000, f)
    reactor.run()

if __name__ == '__main__':
    main()

readServer() is being called just fine, but it never seems to collect any of the data. I've read somewhere that this might have to do with QDataStream's << operator because python isn't exactly sending it in pieces like Qt expects.

I admit I'm not very savvy with C++ or Qt, but the idea of the project is to write a client to work with an existing twisted server, so while the client can be changed I'm left with no choice but to make it work with this server.

Thanks in advance for any help.

A: 

An important thing to understand about TCP is that it is not a transport for messages (or "chunks") of a particular size. It is a transport for a stream of bytes. When you write something like:

if (socket.bytesAvailable() < (int)sizeof(quint16))
    return;

then you'd better have a loop somewhere that's invoking this code again, because there's no guarantee that the first time around you'll get all the bytes you need to get past this check.

You didn't share any of the code that's responsible for sending data to the echo server, so it's impossible to actually know why your Qt client isn't getting the data you expect it to get, but given the above I wouldn't be surprised if it involves incorrect buffering of incomplete data.

Make sure that if you decide not to read from the socket because there isn't enough data, you try reading from it again later after more data might have arrived. A good way to do this is to actually always read the data into an application buffer so that you can use select() or epoll() or what have you to tell you when there is more data available on the socket. Then just operate on the application buffer.

Jean-Paul Calderone
Thank you, I've read a lot about this and probably need to read more. As I said this is my first crack at this, and while this didn't turn out to be the issue I'll keep it in mind.
jeremyhappens
A: 

The issue turned out to be QDataStream, which is apparently more than just a little particular about the data it's reading.

Thankfully, I discovered QDataStream::readRawData which liked data being sent by python a lot better (further I discovered this had nothing to do with twisted, but the python socket implementation itself.) The final code looked like this:

//use socket to construct a QDataStream object, like before
QDataStream in(&socket); 
//in.setVersion(QDataStream::Qt_4_0);
char buffer[1024] = {0};
//readRawData takes a char to dump to and the length, 
//so I'm sure there is a better way to do this. It worked for my example.
in.readRawData(buffer, socket.bytesAvailable()); 
QString result;
result = buffer;
ui->resultLabel->setText(result);
jeremyhappens