PDA

View Full Version : How do I use QTcpSocket properly ?



mnemonic_fx
27th March 2007, 20:04
bool CMsgClient::SendPacket(const void *buf, size_t len)
{
QTcpSocket tcpSocket;
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (const char*)buf;
out.device()->seek(0);

tcpSocket.write(block, len);

return true;
}

I'm trying to send a data from buf, but when I debug it, the block byte array don't have the similar data as buf. Can anybody advise me on how to use QTcpSocket ?

e8johan
27th March 2007, 20:16
Two things:

#1 You allocate the socket on the heap, and then return from your method before it has finished sending. You need to wait for it before exiting your method.

#2 Why don't you use the qint64 write ( const char * data, qint64 maxSize ) method directly, and skip the buffering.

mnemonic_fx
28th March 2007, 14:04
Ok, this is what I change :

bool CMsgClient::SendPacket(const void *buf, size_t len)
{
QTcpSocket tcpSocket;
tcpSocket.write((const char*)buf, len);
}

I send the packet to localhost 127.0.0.1,
but, still I don't see any packet sent to the localhost.
Why is that ?

Do I need to write specific code to send the 'buf' ?
Is there anything that I should pay attention for ?
Does it depends on the endpoint of the network ?

Sorry, I'm a newbie in Qt, I'm just surprised by the small amount of code that I need to write to send data through TCP connection.

Please help. :)

fullmetalcoder
28th March 2007, 15:37
Ok, this is what I change :

bool CMsgClient::SendPacket(const void *buf, size_t len)
{
QTcpSocket tcpSocket;
tcpSocket.write((const char*)buf, len);
}

I send the packet to localhost 127.0.0.1,
but, still I don't see any packet sent to the localhost.
Why is that ?

Are you sure the packet will be send to localhost? It really shouldn't if you are using this code...
As e8johan said, heap allocation is seldom used in network programming because the socket is most likely to be destroyed before completing its task
your socket doesn't seem to be connected to any host... QAbstractSocket::connectToHost() (http://doc.trolltech.com/latest/qabstractsocket.html#connectToHost)
If you really want to allocate you socket on heap you should give him some more time (potientially freezing GUI but that's another issue...) :

QTcpSocket sock;
sock.connectToHost("127.0.0.1", 0);
sock.waitForConnected();
sock.write((const char*)buf, len);
sock.waitForBytesWritten();
Note : Heap allocation will be IMPOSSIBLE if your data is too long and needs to be split into several packets by QTcpSocket, internally. In this case only the first packet (or maybe the two first if you're lucky) will be sent...

mnemonic_fx
28th March 2007, 17:33
Sorry, I don't write the complete code,
I connect to a host from a class that inherits from QThread,
and I run a server at port 9060.

something like this :




CMsgSession::run()
{
while (!workerQuitFlag) {
const int Timeout = 5 * 1000;

QTcpSocket tcpSocket;
tcpSocket.connectToHost(serverName, serverPort);

if (!tcpSocket.waitForConnected(Timeout)) {
emit error(tcpSocket.error(), tcpSocket.errorString());
return;
}
}
}



I was expecting that the connection is still established while the tread is running, so I write the data from another class, which is called after the thread is executed.

fullmetalcoder
28th March 2007, 18:23
It looks like you're getting something wrong : QTcpSocket is a class. You can instantiate objects in two ways : either on heap (as you're apparently doing) so that they get deleted when the local scope is left or dynamically (through "new" operator) so that they remain until explicit deletion. As far as I understand your design you'll need the second way. Indeed, creating a new QTcpSocket in a function after having established a connection with *another* QTcpSocket won't lead anywhere... On the contrary you should add a member to your thread class ("QTcpSocket *pSocket;", for instance), initialize it properly in the run() function and then send data through it in your sendPacket() function. Another thing worth being said is that QTcpSocket internally manages "packets". i.e. it splits data if necessary and sends packets one by one in the right order...

mnemonic_fx
28th March 2007, 20:21
Indeed, creating a new QTcpSocket in a function after having established a connection with *another* QTcpSocket won't lead anywhere... On the contrary you should add a member to your thread class ("QTcpSocket *pSocket;", for instance), initialize it properly in the run() function and then send data through it in your sendPacket() function.

I'm very sorry again, because I don't write my complete code on this question.
I already done what you have said, but I still get a -1 return from
qint64 write ( const char * data, qint64 maxSize ) method.

I initialized my socket at CMsgSession : public QThread, and I send the packet from CMsgClient class. Once I use your code :



QTcpSocket sock;
sock.connectToHost("127.0.0.1", 9060);
sock.waitForConnected();
sock.write((const char*)buf, len);
sock.waitForBytesWritten();


I could send the data, but suddenly my local server says that the client close the socket.. :confused:

What when wrong ?

Is there a problem with my server ?

mnemonic_fx
28th March 2007, 21:53
Ok, I understand my previous problem, now I got this error when I access write function from another class :

The program breaks at :

private:
Q_DECLARE_PRIVATE(QIODevice)
Q_DISABLE_COPY(QIODevice)

I think I need to inherit the class CMsgClient which references the function QTcpSocket CMsgSession::tcpSocket->write(..., ....) from QObject.
Is that true ?
Is there any other way ?

Do I need to inherit from QObject, everytime I use Qt class ?

jacek
28th March 2007, 22:09
Ok, I understand my previous problem, now I got this error when I access write function from another class :
Could you post the exact error message?


Do I need to inherit from QObject, everytime I use Qt class ?
No, you don't. Otherwise you wouldn't be able to use Qt classes in main(), not mentioning that some Qt classes aren't derived from QObject.

fullmetalcoder
29th March 2007, 09:26
I initialized my socket at CMsgSession : public QThread, and I send the packet from CMsgClient class. Once I use your code :



QTcpSocket sock;
sock.connectToHost("127.0.0.1", 9060);
sock.waitForConnected();
sock.write((const char*)buf, len);
sock.waitForBytesWritten();
I could send the data, but suddenly my local server says that the client close the socket.. :confused:

What when wrong ?

Is there a problem with my server ?
Nop... If that's really the code you're using (not talking about completeness here just exactitude...) Then the connection must close as soon as the execution leaves the scope where your socket is instantiated (loop, function, whatever) because you don't use dynamic allocation but heap allocation... Thus the socket object is destroyed and stops communicating with your server... I think you should read some more about OOP and C++...

mnemonic_fx
29th March 2007, 11:32
Nop... If that's really the code you're using (not talking about completeness here just exactitude...) Then the connection must close as soon as the execution leaves the scope where your socket is instantiated (loop, function, whatever) because you don't use dynamic allocation but heap allocation... Thus the socket object is destroyed and stops communicating with your server... I think you should read some more about OOP and C++...

When I call the function like this : (session is a pointer to class object)



session->tcpSocket.write((const char*)buf,len);
session->tcpSocket.waitForBytesWritten();


I get this error :

Unhandled exception at 0x670afb8a (QtCored4.dll) in MyProgram.exe: 0xC0000005: Access violation reading location 0xcdcdcdd9.

and it's break at this location :



private:
-> Q_DECLARE_PRIVATE(QIODevice)
Q_DISABLE_COPY(QIODevice)


I access the tcpSocket object that was created in a running thread.
If I want to maintain the connection what should I do ?
create a static object ?


By the way isn't heap allocation & dynamic allocation is the same thing, just with different terms ?

I read this on a book, chapter 20.3 of "An Introduction to Design Patterns in C++ with Qt" :



The heap or free storage (dynamic storage): Objects created via new are examples.
The lifetime of a heap object is determined entirely by the use of new and delete.
In general, the allocation and freeing of heap objects should be in carefully encapsulated classes.


And I read this on a book, chapter 3 of "Memory Management, Algorithms and Implementations in C-C++" :


Heap memory allocation, also known as dynamic memory allocation
(DMA), consists of requesting memory while an application is running
from a repository known as the heap.


:confused:

fullmetalcoder
29th March 2007, 18:29
Generally speaking accessing class members directly is wrong. Instead you should provide wrapper functions/slots/whatever to handle that
Sounds like your QTcpSocket object is an object and not a pointer. This is also considered as bad design because it is NOT a type which can be copied (noticed the Q_DISABLE_COPY() macro ?) just like basic types (int, QString, QPixmap QList<>, ... for instance) which implies that in most cases, and especially when using such objects outside of their creation scope, they should be created through new and accessed via pointers...
There seems to be quite a misunderstanding about semantics... I used to to think that "heap allocation" referred to objects created as objects (i.e. without "new" operator) which were automatically deleted when the program leaved the creation scope whereas "dynamic allocation" referred to process of creating objects via "new" and deleting them manually with "delete". I might have been misleaded as far as names are concerned (and I shall investigate this) but my remarks still stand in your case : use pointers when dealing with network objects!
Hope this helps. :)

jacek
29th March 2007, 21:19
session->tcpSocket.write((const char*)buf,len);
How do you initialize buf and len?


and it's break at this location : (...)
Could we see the backtrace?

mnemonic_fx
29th March 2007, 21:33
Ok, I think I understand about dynamic allocation and using pointers, I try to use that, but still.. it doesn't solve my problem.

I declare CMsgSession *session on CMsgClient private member.
I write this on the constructor :



CMsgClient::CMsgClient()
{
session = new CMsgSession();
}


And I declare QTcpSocket *tcpSocket on CMsgSession public member, I write this on the constructor :



CMsgSession::CMsgSession(QObject *parent) : QThread(parent), workerQuitFlag(false)
{
tcpSocket = new QTcpSocket();
}


and I access the tcpSocket like this :

session->tcpSocket->write(buf, len);

it causes access violation, it's getting more confusing,
but thanks anyway..