0

I am developing Client-Server application in C++ using Qt framework, but the clients can be android phones and computers(Qt client app) Now i'm having troubles to handle Reception of data on the server side; the server is not receiving data properly.

First, I got things working nicely between the server(Qt app) and the client(Qt app) using these methods for sending and receiving: The size of the message is kept at the beginning of the packet to help check whether the whole message is received or not.

This is the method to send message to the clients

void Server::send(const QString &message)
{
    QByteArray paquet;
    QDataStream out(&paquet, QIODevice::WriteOnly);

    out << (quint16) 0; // just put 0 at the head of the paquet to reserve place to put the size of the message
    out << message; // adding the message
    out.device()->seek(0); // coming back to the head of the paquet
    out << (quint16) (paquet.size() - sizeof(quint16)); // replace the 0 value by the real size


    clientSocket->write(paquet); //sending...

}

This slot is called every time a single paquet is received.

void Server::dataReceived()
{
    forever 
    {
        // 1 : a packet has arrived from any client

        // getting the socket of that client (recherche du QTcpSocket du client)
        QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
        if (socket == 0) 
            return; 

        QDataStream in(socket);

        if (dataSize == 0) // if we don't know the size of data we are suppose to receive...
        {
            if (socket->bytesAvailable() < (int)sizeof(quint16)) // we haven't yet receive the size of the data completly then return...
                 return;

            in >> dataSize; // now we know the amount of data we should get
        }

        if (socket->bytesAvailable() < dataSize) 
            return;

        // Here we are sure we got the whole data then we can startreadind
        QString message;
        in >> message;

        //Processing....

        dataSize = 0; // re-initialize for the coming data
    }
}

This is working well when the server is talking with the Qt app Client, because the same methods are used there, and the size of quint16 will remain the same hover it doesn't work with android client, then i tried another way in which i wanted to ignore the size of the message sent, but format the message in a way such that i can know where it starts and where it ends, then with some controls i can get it however i'm stuck here, cause the data read doesn't contain anything when printed, but his size has a value(which even vary according to the amount of text the client send)!

void Server::dataReceived() // a packet is received!
{

    QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
    if (socket == 0)
        return;


    QByteArray data= socket->readAll(); //reading all data available
    QString message(data)

    qDebug() << data;        // this prints nothing!
    qDebug() << data.size();//  But this prints a non null number, wich means we got something, and that number varies according to the amount of text sent!
    qDebug() << message;    // this also prints notghing!

} 

PS: it's not working even for the Qt app Client.

Can you help me find out what's wrong, i'm a bit confused how the tcp protocol is handling the data, and if you could and also advise me a good way for doing this.

here is the android class I made for the purpose

class QTcpSocket implements Runnable {

    private String ip="";
    private int port;
    private Socket socket;
    private PrintWriter printWriter;

    private DataOutputStream dataOutputStream;
    private DataInputStream dataInputStream;

    public QTcpSocket(String ip, int port) {
        this.ip = ip;
        this.port = port;
    }

      public void setIp(String ip) {
          this.ip = ip;
      }

      public String getIp() {
          return this.ip;
      }

    public void setPort(int port) {
        this.port = port;
    }

    public void run() {
        try {
            socket = new Socket(this.ip, this.port);
            dataOutputStream = new DataOutputStream( socket.getOutputStream() );
            dataInputStream = new DataInputStream(socket.getInputStream());
            String response = dataInputStream.readUTF();
            dataOutputStream.writeUTF("Hello server!");


        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    public void sendMessage(String message) {
        try {

            dataOutputStream.writeUTF(message);
        }catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void disconnect() {
        try {

            printWriter.flush();
            printWriter.close();
            socket.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean isClosed() {
        return socket.isClosed();
    }
}
Xsmael
  • 3,624
  • 7
  • 44
  • 60
  • 1
    You should not have made a new dataReceived() but let your android client send the size of the message first too. Please try again to do so. Do not use writeUTF but write. Please tell why you concluded it could not work with an android client. – greenapps Mar 23 '15 at 17:34
  • `sendMessage`. I dont see that used in android code. – greenapps Mar 23 '15 at 17:39
  • `// But this prints a number, wich means we got somthing`. 0? Better tell what the number is of course. – greenapps Mar 23 '15 at 17:57
  • How much is `sizeof(quint16)`? 2? – greenapps Mar 23 '15 at 18:00
  • @greenapps `// But this prints a number, wich means we got somthing ` i'm getting a positive number according to the number of characters the client sent. sizeof(quint16) = 2 indeed. – Xsmael Mar 23 '15 at 18:24
  • ~@greenapps The thing is i'm not very familiar with java/android i'm not sure of the way to do it. i'm more used to C++ and Qt. sendMessage is there it's a method, you should scroll down to see it – Xsmael Mar 23 '15 at 18:27
  • Yes i see it declared. But not called. You are not using it. Positive number equals number of bytes send? Please show in code exactly the string you send and then tell the number. – greenapps Mar 23 '15 at 18:54
  • Is it equal to the number of characters send or twice as much? – greenapps Mar 23 '15 at 18:59
  • I advise you to make a hex representation of the data byte array as received by the server. Then log that. You then see much better all the values. – greenapps Mar 23 '15 at 19:02
  • i'm calling it from outside and previously with this commented line `//sendMessage("Heoollloo serv!!!");` in `run()` – Xsmael Mar 23 '15 at 19:03
  • @greenapps the size is equal to the number of characters sent + 2 – Xsmael Mar 23 '15 at 19:04
  • You cannot send it there as the outPutStream is not yet determined. – greenapps Mar 23 '15 at 19:05
  • how do you do that hex representation ? don't worry i wasn't sending there, i just forgot to clean this. it wont even work and the server will not feel anything... – Xsmael Mar 23 '15 at 19:09
  • 1
    Google for 'c++ write byte as hex'. As an alternative replace in 'data' all bytes with value 0 by value 20 and print again. I think you see nothing printed because the first byte is 0. You could also replace with 'X'. – greenapps Mar 23 '15 at 19:26
  • Did you already replace writeUTF() by write() ? Please do. – greenapps Mar 23 '15 at 19:29
  • @greenapps You were right! when i test all the bytes, only the first one is 0 and when I replace it with 20(or anything else, is there a reason you choose 20 or 'X' ?) then i can print it! Also, using write() instead of writeUTF() solves the problem without the need to replace 0s on server side. Thank You very much! I would like also a small explanation of what is happening behind, why write UTF doesn't work properly, and how did you figure out that 0 char problem ? Thanks! – Xsmael Mar 24 '15 at 02:58

1 Answers1

1

Replace in 'data' all bytes with value 0 by value 20 and print again. I think you see nothing printed because the first byte is 0. You could also replace with 'X'. Did you already replace writeUTF() by write() ?

20 is the space character. But then you also see nothing printed so better use a X char. Strings get printed until a \0 char (which indicates the end of a string) is met. Because nothing was printed i supposed one right at the beginning. So writeUTF causes that leading 0. I could only explain that if all chars had doubled. What was the first char you sent?

But now: send size-of-message first so it equals your qt client.

greenapps
  • 11,154
  • 2
  • 16
  • 19
  • Yes it is working better with write(), i replaced. is it not 32 the space character ? AFAIK from the ASCII table. for sending size of message first, i'm using quint16 instead of int because its sizeof() will not change from one system to another, i'm not sure for java because the application will fail if ever change – Xsmael Mar 24 '15 at 15:45
  • You better use quint32 right away as otherwise you cannot transfer images with a normal size. Haha 0x20==32. – greenapps Mar 24 '15 at 18:26
  • i think so. If i use a long it should work, because long in Java takes 8bytes and sizeof(quint64) = 8 – Xsmael Mar 26 '15 at 05:34