I have big Qt, Linux, C++ and Web programming experience, but this case blows up my brain!
This code works on many sites, many different machines with many different XML files, but does not work with some files on some machines without the rules. I have tried everything, blocking and non-blocking sockets, w and w/o socket flush.
On server side, I dump bad TCP stream with tcpdump eg.
tcpdump -w <bin_dump.log> host <client_IP>
tcpdump -w <bin_dump.log> host <client_IP>
To copy to clipboard, switch view to plain text mode
and then analyze them in Wireshark. As I can understand server missed one packet (maybe the first one) and could not receive the whole message.
On client side, I made binary dump of TCP stream sent and send it with
dd if=./tcp.bin > /dev/tcp/<server_ip>/<server_port>
dd if=./tcp.bin > /dev/tcp/<server_ip>/<server_port>
To copy to clipboard, switch view to plain text mode
and everything is fine then. So, the problem is in my client side app.
Is such a cases the only one solution is to manually add one extra char into XML tag and change the size of the file, eg. 7604 bytes to 7605 bytes, and then the file was sent. But, the files smaller and bigger that the one can be sent w/o problems. There is no rules about size. Sometimes it happens on file with 823 bytes, sometimes with 12666 bytes.
Relevant code is:
/**
* Send XML file
* @param sMsg Message prefix
* @param sFile XML file name
*/
void TXmlSender::tcpSendXmlFile(const QString& sMsg, const QString& sFileName)
{
xmlFileToString(sFileName, sXml);
TXmlTCPCli *tcpCli = new TXmlTCPCli(m_sHostIP, m_nHostPort, this);
connect(tcpCli, SIGNAL(onResponse(const QString&, const QString&)),
this, SLOT(slot_onSendXmlFile(const QString&, const QString&)));
QString sSend
= m_sLokalID
+ ": " + sMsg
+ " " + sXml;
tcpCli->sendMsgReq(sSend);
}
/**
* Send XML file
* @param sMsg Message prefix
* @param sFile XML file name
*/
void TXmlSender::tcpSendXmlFile(const QString& sMsg, const QString& sFileName)
{
QString sXml;
xmlFileToString(sFileName, sXml);
TXmlTCPCli *tcpCli = new TXmlTCPCli(m_sHostIP, m_nHostPort, this);
connect(tcpCli, SIGNAL(onResponse(const QString&, const QString&)),
this, SLOT(slot_onSendXmlFile(const QString&, const QString&)));
QString sSend = m_sLokalID + ": " + sMsg + " " + sXml;
tcpCli->sendMsgReq(sSend);
}
To copy to clipboard, switch view to plain text mode
TXmlTCPCli is trivial TCP client class and main part of them is:
/**
* SLOT: On connected to host
*/
void TXmlTCPCli::onConnected()
{
QTcpSocket *socket
= qobject_cast<QTcpSocket
*>
(sender
());
if (socket == 0) {
return;
}
out << (quint16)0;
out << m_sMsg;
out.device()->seek(0);
out << (quint16)(bArrMsg.size() - (int)sizeof(quint16));
while (!bArrMsg.isEmpty()) {
if (!socket->isWritable()) {
LOG("Error! Could not write to socket2!");
break;
}
qint32 sentNow = socket->write(bArrMsg);
if (sentNow < 0) {
LOG("Error! sendMsgImpl: Could not write to socket!");
break;
}
else {
bArrMsg.remove(0, sentNow);
// socket->flush();
LOG("sendMsgImpl: Sent " << sentNow << ", Rest: " << bArrMsg.size());
}
}
socket->disconnectFromHost();
}
/**
*/
void TXmlTCPCli::onDisconnected()
{
QTcpSocket *socket
= qobject_cast<QTcpSocket
*>
(sender
());
if (socket != 0) {
socket->deleteLater();
}
this->deleteLater();
}
/**
* SLOT: On connected to host
*/
void TXmlTCPCli::onConnected()
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
if (socket == 0) {
return;
}
QByteArray bArrMsg;
QDataStream out(&bArrMsg, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << (quint16)0;
out << m_sMsg;
out.device()->seek(0);
out << (quint16)(bArrMsg.size() - (int)sizeof(quint16));
while (!bArrMsg.isEmpty()) {
if (!socket->isWritable()) {
LOG("Error! Could not write to socket2!");
break;
}
qint32 sentNow = socket->write(bArrMsg);
if (sentNow < 0) {
LOG("Error! sendMsgImpl: Could not write to socket!");
break;
}
else {
bArrMsg.remove(0, sentNow);
// socket->flush();
LOG("sendMsgImpl: Sent " << sentNow << ", Rest: " << bArrMsg.size());
}
}
socket->disconnectFromHost();
}
/**
*/
void TXmlTCPCli::onDisconnected()
{
QTcpSocket *socket = qobject_cast<QTcpSocket *>(sender());
if (socket != 0) {
socket->deleteLater();
}
this->deleteLater();
}
To copy to clipboard, switch view to plain text mode
When this code catch some files, server waits, and waits and then timeout and disconnect. The rest of the code works fine, and send TCP messages, receive TCP messages etc. This application also has QTcpServer listen on same port. Client machines was Mint32 Maya, Ubuntu 11.10 and Qt is v 4.8.1.
How to resolve this? How to debug QTcpSocket on lower level? Why many files sent normally but other only with change the size? Qt bug? Memory leak? Any hint?
Bookmarks