I try to send data over the network, but the server I've programmed doesen't get the data.
This code worked befor:
void MainWindow::send()
{
QByteArray qbarr;
QDataStream qdstrm(&qbarr, QIODevice::WriteOnly);
int iCount = qlist->count();
QProgressDialog qprogrsdSend(QString("Sending..."), QString("Cancel"), 0, iCount, this);
qdstrm.setVersion(QDataStream::Qt_4_6);
qprogrsdSend.setWindowModality(Qt::WindowModal);
for(int i = 0; i < iCount; i++)
{
if(qprogrsdSend.wasCanceled())
break;
qdstrm << (quint16)0;
qdstrm << (*qlist)[i].data();
qdstrm.device()->seek(0);
qdstrm << (quint16)(qbarr.size() - sizeof(quint16));
qprogrsdSend.setValue(i);
qtcpsoClient->write(qbarr);
qtcpsoClient->flush();
qtcpsoClient->waitForBytesWritten();
qbarr.clear();
}
qlblStatus2->setText("File is send.");
}
But it Takes to many time to send each elemt from qlist. Now I tried to modify the methode, so that first all elements from qlist has been saved in qbarr. And than I send the File. This is the code that doesnt work:
void MainWindow::send()
{
QByteArray qbarr;
QDataStream qdstrm(&qbarr, QIODevice::WriteOnly);
int iCount = qlist->count();
QProgressDialog qprogrsdSend(QString("Sending..."), QString("Cancel"), 0, iCount, this);
qdstrm.setVersion(QDataStream::Qt_4_6);
qprogrsdSend.setWindowModality(Qt::WindowModal);
qdstrm << (quint16)0;
for(int i = 0; i < iCount; i++)
{
if(qprogrsdSend.wasCanceled())
break;
qdstrm << (*qlist)[i].data();
qprogrsdSend.setValue(i);
}
qdstrm.device()->seek(0);
qdstrm << (quint16)(qbarr.size() - sizeof(quint16));
qtcpsoClient->write(qbarr);
qtcpsoClient->flush();
qtcpsoClient->waitForBytesWritten();
qbarr.clear();
qlblStatus2->setText("File is send.");
}
And here is the methode I use to read the data:
void QServerThread::onReadyRead(void)
{
if(read == false)
{
read = true;
emit reading(true);
}
while(!qtcpsoClient->atEnd())
{
QDataStream qdstrmIn(qtcpsoClient);
QDataStream qdstrmOut(qfile);
QByteArray qbarrData;
quint16 qui16BlockSize = 0;
int iVersion = qdstrmIn.version();
qdstrmIn.setVersion(iVersion);
qdstrmOut.setVersion(iVersion);
if(qtcpsoClient->bytesAvailable() < (int)sizeof(quint16))
break;
qdstrmIn >> qui16BlockSize;
if(qtcpsoClient->bytesAvailable() < qui16BlockSize)
break;
qdstrmIn >> qbarrData;
qdstrmOut << qbarrData.data();
qfile->flush();
}
read = false;
emit reading(false);
}
I hope somebody can help me.
Thanks
Paul
Couldn't the problem be in your server? I suppose you connect your onReadyRead to readyRead singal of the socket. That signal is emitted once per a chunk of data received. So if you send all your data at once, it is possible the signal gets emitted only once. I suppose qtcpsoClient is the socket. Now, I can see this happening:
You ask bytesAvailable() < somesize before that much data arrived yet. In that case you read a size, but break out right after that and on next read you already lost your size information and read garbage.
This might not be a problem before as you send multiple short messages, and every message managed to fully arrive before you asked for the data size. The bug was still there though.
On a sidenote. In your original client code - why did you flush() and waitForBytesWritten() after every write? This may be the reason why it was so slow.
[edit: corrected based on Sergey Tachenov's comment]
Related
I have two mac apps that communicate with each other using QLocalSocket.
Able to send the received QString but not able to send the received QImage Below is my code.
SERVER SIDE CODE
QImage image(":/asset/logo_active.png");
QByteArray ba;
qDebug() << image.sizeInBytes() <<image.size();
ba.append((char *)image.bits(),image.sizeInBytes());
qDebug() <<ba.size(); //262144
this->mSocket->write(ba);
if(!this->mSocket->waitForBytesWritten(-1))
{
qDebug() << "writen Bytes error " << this->mSocket->errorString();
}
this->mSocket->flush();
CLIENT SIDE CODE
connect(mLocalSocket,&QLocalSocket::readyRead, [&]() {
QByteArray ba;
ba = mLocalSocket->readAll();
qDebug() << "size is" << ba.size(); // size is 0
QImage image((uchar *)ba.data(),1024,768,QImage::Format_RGB32);
ui->labelStream->setPixmap(QPixmap::fromImage(img));
});
at sender 262144 is the byte-array size
but at the receiver, byte-array size is 0
Do let me know if I am missing anything.
Thanks In Advance
Finally I got the solutions I used QDataStream below is the code example.
SERVER SIDE CODE:
QDataStream T(mSocket);
T.setVersion(QDataStream::Qt_5_7);
QByteArray ba;
ba.append((char *)img.bits(),img.sizeInBytes());
T << ba;
mSocket->flush();
CLIENT SIDE CODE
QByteArray jsonData;
QDataStream socketStream(mLocalSocket);
socketStream.setVersion(QDataStream::Qt_5_7);
for (;;) {
socketStream.startTransaction();
socketStream >> jsonData;
if (socketStream.commitTransaction()) {
QImage image((uchar *)jsonData.data(),640,480,QImage::Format_RGB888);
ui->labelStream->setPixmap(QPixmap::fromImage(image));
}else {
// the read failed, the socket goes automatically back to the state it was in before the transaction started
// we just exit the loop and wait for more data to become available
break;
}
}
Thanks, Everyone for your support also Stackoverflow.
I am creating a script in QT for reading the format packages (AA), (BB), etc from serial port. I open the serial port, but when I go to check inside the QByteArray values, comes back that I could not read any value.
This is my code
...
QSerialPort *serialPort = new QSerialPort();
serialPort->setPortName("ttyUSB0");
serialPort->setParity(QSerialPort::NoParity);
serialPort->setBaudRate(QSerialPort::Baud9600, QSerialPort::AllDirections);
serialPort->setStopBits(QSerialPort::OneStop);
serialPort->setFlowControl(QSerialPort::NoFlowControl);
serialPort->open(QIODevice::ReadOnly);
if (serialPort->isOpen()) {
qDebug() << "Serial port is open...";
QByteArray datas = serialPort->readAll();
if (datas.size() == 0) {
qDebug() << "Arrived data: 0";
} else {
for (int i = 0; i < datas.size(); i++){
if (datas.at(i)) {
qDebug() << datas[i];
}
}
}
} else {
qDebug() << "OPEN ERROR: " << serialPort->errorString();
}
serialPort->close();
qDebug() << "...serial port is closed!";
return 0;
...
You called readAll() immediately after open(). It probably took the computer a few nanoseconds to get from one to the other.
At 9600 baud, each byte of data takes slightly more than one millisecond to transfer. It would be absolutely impossible for any data to have arrived in that short an interval, so that's why you got no data.
Serial ports don't begin buffering incoming data until you open them (how could they, what baud rate and other settings would be used for receiving and buffering when no program has the port open?)
Use either a blocking read function of some sort (such as readLine()) or an event loop that reacts to data when it arrives.
I'm working with a serial device.
The QSerialPort is in a separate thread.
Thread is created this way:
QThread* serialthread = new QThread;
Serial* serial = new Serial();
serial->moveToThread(serialthread);
When Data is available this signal in my thread worker is emited:
void Serial::process()
{
serialport = new QSerialPort();
connect(this->serialport,SIGNAL(readyRead()),this,SLOT(readyToRead()));
}
void Serial::readyToRead()
{
emit SIG_dataAvailable(this->read());
}
This is the function that reads the data and checks if the data is correct - the second byte on my serial device says how long the rest of the packet is...
QByteArray Serial::read() const
{
QByteArray receivedData;
int length;
receivedData = serialport->readAll();
length = receivedData[1];
if(length != receivedData.length() - 1)
{
qDebug() << "protocol error.";
return NULL;
}
return receivedData;
}
My problem is that the signal QSerialPort::readyRead is emited before the data from the serial device is complete in the buffer. Any idea how to solve this problem?
There is absolutely NO guarantee that you'll get whole data at ONCE. You can solve this problem in some ways.
1) If you have fixed size package you can do something like this:
void foo::onSerialRead()
{
//! Is there whole datagram appears?
if (m_serial->bytesAvailable() < ::package_size) {
//! If not, waiting for other bytes
return;
}
//! Read fixed size datagram.
QByteArray package = m_serial->read(::package_size);
//! And notify about it.
emit packageReady(package);
}
2) If your package size may vary. Then you have to include "hader" in to your package. This header should contain at least "start" byte and data size (Its second byte in your case). And header shuld be fixed size. Then you can do something like this:
void foo::onSerialRead()
{
static QByteArray package;
static bool isHeaderRead = false;
static quint8 startByte = 0;
static quint8 dataSize = 0;
//! Is there whole header appears?
if (m_serial->bytesAvailable() < ::header_size) {
//! If not, waiting for other bytes
return;
}
if (!isHeaderRead) {
//! Read fixed size header.
package.append(m_serial->read(::header_size));
QDataStream out(&package);
out >> startByte;
//! Check is it actually beginning of our package?
if (Q_UNLIKELY(startByte != ::protocol_start_byte)) {
return;
}
out >> dataSize;
isHeaderRead = true;
}
//! Check is there whole package available?
if (Q_LIKELY(dataSize > m_serial->bytesAvailable())) {
//! If not, waiting for other bytes.
return;
}
//! Read rest.
package.append(m_serial->read(dataSize));
//! And notify about it.
emit packageReady(package);
package.clear();
isHeaderRead = false;
}
And there is absolutely no point in putting your QSerial in to different thread.
The following code is intended to display an Image sent over network. I sent a header of 16 bytes which I use to calculate the size of image that follows and then read that many bytes and display the image.
I used the concept at this link Tcp packets using QTcpSocket
void socket::readyRead()
{
while(socket->bytesAvailable() > 0) {
quint8 Data[16];
socket->read((char *)&Data,16);
img_size = (((quint8)Data[1]<<8)+ (quint8)Data[0]) * (((quint8)Data[3]<<8)+ (quint8)Data[2]) * 1;
QByteArray buffer = socket->read(img_size);
while(buffer.size() < (img_size))
{
// qDebug() << buffer.size();
socket->waitForReadyRead();
buffer.append(socket->read((img_size)-(buffer.size()) ));
}
unsigned char* imgdatara = (unsigned char*)&buffer.data()[0];
if( !image )
image = new QImage(imgdatara,32,640,QImage::Format_Grayscale8);
else
{
delete image;
image = new QImage(imgdatara,32,640,QImage::Format_Grayscale8);
}
emit msg(image);
}
}
My GUI says "not responding". How should I solve this?
Thanks
This is 100% working code from the book of Max Schlee's "Qt 4.8 Professional programming". This is not a simple question, because on the readyRead() signal you can receive:
1. A complete block
2. Only a part of block
3. Several blocks together
void MyClass::onReceive()
{
QDataStream in(m_pClient);
in.setVersion(QDataStream::Qt_4_6); // Your version. Not necessary.
for(;;)
{
if(m_nextBlockSize == 0)
{
if(m_pClient->bytesAvailable() < sizeof(m_nextBlockSize))
{
break;
}
else
{
in >> m_nextBlockSize;
}
}
if(m_pClient->bytesAvailable() < m_nextBlockSize)
{
break;
}
// Here you have each complete block
processYourBlockHere(); // <=====
m_nextBlockSize = 0;
}
}
Update: useful links for you: Serializing Qt Data Types and QDataStream
I have a server application which sends some xor encrypted strings. I am reading them from my QT client application. Sometimes, the server is slower and I am not able to receive the entire string. I have tried something like below but it gets stuck ( see the comment below). How can I wait until I have the entire data. I tried bytesAviable() but then again i get stuck (infinite loop)
QTcpSocket * sock = static_cast<QTcpSocket*>(this->sender());
if (key == 0)
{
QString recv(sock->readLine());
key = recv.toInt();
qDebug() << "Cheia este " << key;
char * response = enc_dec("#AUTH|admin|admin",strlen("#AUTH|admin|admin"),key);
sock->write(response);
}
else
{
busy = true;
while (sock->bytesAvailable() > 0)
{
unsigned short word;
sock->read((char*)(&word),2);
qDebug()<<word;
//Sleep(100); if i do this than it works great!
QByteArray bts = sock->read(word);
while (bts.length() < word)
{
char bit; //here get's stuck
if (sock->read(&bit,1) > 0)
bts.append(bit);
sock->flush();
}
char * decodat = enc_dec((char*)bts.data(),bts.length() - 2,key);
qDebug() << decodat;
}
}
I don't know what the meaning of key == 0 is, but you are almost certainly misusing available(), like almost everybody else who has ever called it, including me. It tells you how much data can be read without blocking. It has nothing to do with how much data may eventually be delivered down the connection, and the reason is that there are TCP APIs that can tell you the former, but not the latter. Indeed the latter doesn't have any real meaning, considering that the peer could keep writing from now until Doomsday. You should just block and loop until you have read the amount of data you need for the next piece of work.
I offer you to do the following:
QObject::connect(this->m_TCPSocket, SIGNAL(readyRead()), this, SLOT(processRecivedDatagrams()));
Some explanation:
It is convinient to create a class instance of which will manage network;
One has the member which is pointer on TCPSocket;
In constructor implement connection of signal from socket readyRead() which is emmited when needed data was delivered with SLOT(processRecivedDatagrams()). which is responsible for processing recived datagrams/ in this case it is processRecivedDatagrams(), also implement this slot
Mind that class which manages network has to inherit from QObject and also in its declaration include macrosQ_OBject` for MOC.
update:
i also offer you to store recived data in container like stack or queue this will allow you to synhronize sender and reciver (container in this case acts like buffer)
// SLOT:
void Network::processRecivedDatagrams(void)
{
if (!this->m_flagLocked) // use analog of mutex
{
this->m_flagLocked = true; // lock resource
QByteArray datagram;
do
{
datagram.resize(m_TCPSocket->pendingDatagramSize());
m_TCPSocket->readDatagram(datagram.data(), datagram.size());
}
Qt::String YourString; // actualy I don`t remember how to declare Qt string
while (m_TCPSocket->hasPendingDatagrams());
QDataStream in (&datagram, QIODevice::ReadOnly);
in >> YourString
--numberOfDatagrams;
}
this->m_flagLocked = false; // unlock resource
}
}