Im creating TCP Server/Client application in QT Creator framework. I want to get some data from UI input field and send it over TCP.
Im doing something like this in client application:
void MainWindow::on_btn_login_clicked()
{
QByteArray text = (ui->login_input->text()).toLocal8Bit();
char* out = text.data();
connection->ConnectAndSendData(out);
}
and in the ConnectAndSendData function:
void TcpConnect::ConnectAndSendData(const char* data)
{
socket = new QTcpSocket(this);
int port = 1234;
socket->connectToHost("localhost", port);
if(socket->waitForConnected(3000))
{
qDebug() << "connected to s. localhost at port " << port;
socket->flush();
socket->write(data, sizeof(data));
qDebug() << data << "\n";
socket->waitForReadyRead();
char* serverresponse;
socket->read(serverresponse, 128);
if(serverresponse == MESSAGE_LOGINRQ)
socket->write(data);
socket->flush();
socket->close();
}
else
{
/**/
}
}
and the data in line socket->write(data, sizeof(data)); is properly send to server, but when server echoes it, it looks like "something/x00/x00/x00/x00" or somethinglike that. Also when i to do something like this:
#define MESSAGE_WANTLOGIN "wanlogin"
socket->write(MESSAGE_WANTLOGIN, sizeof(MESSAGE_WANTLOGIN));
message is messed up with those null signs.
on the server side receiving data look as simple as:
void Thread::readyRead()
{
socket->flush();
QByteArray data = socket->readAll();
qDebug() << "data received: " << data;
if(data == MESSAGE_WANTLOGIN)
{
socket->write(MESSAGE_LOGINRQ);
} else
{
qDebug() << "error not messageloginrq";
}
}
and like u can assume, though i send "wanlogin" message, server receiving something like "wanlogin/x00/x00" and this if obviously returns false.
this trash is applied on the end of data, and this impossible to check what message was send. The other thing is that maximum size of send data is 8 chars, but also to data of this length trash is applied so it looks like "wanlogin/x00/x00"; however, when i type more chars, for example 10, the send data is just cut to 8 signs, with no /x00s.
So my question is how to clear data from those /x00s and how to send more than 1 byte of information(i need it e.g. to send login and password of user). Sorry if there's some stupid mistake, its my first client/server application which also using multithreading for each client.
sizeof(data) is 4 or 8 depending if you are on a 32-bit or 64-bit machine. It is not the size of your data, but the size (in byte) of a pointer.
So what happens is that your actual wanlogin is in fact a 6 character string, and you end up sending 2 more bytes. In this case you are lucky: the char array returned by data() is null-terminated, so you have one extra 0 that you can access, but accessing the second 0 is undefined behavior i.e anything can happen.
The solution is to use strlen() instead of sizeof. Or, better, to directly call write() with a QByteArray by changing ConnectAndSendData(const char* data) to ConnectAndSendData(const QByteArray &data).
void MainWindow::on_btn_login_clicked()
{
const QByteArray text = (ui->login_input->text()).toLocal8Bit();
connection->ConnectAndSendData(text);
}
void TcpConnect::ConnectAndSendData(const QByteArray & data)
{
socket = new QTcpSocket(this);
quint16 port = 1234;
socket->connectToHost("localhost", port);
if(socket->waitForConnected(3000))
{
qDebug() << "connected to s. localhost at port " << port;
socket->write(data);
...
}
...
}
Related
This question already has answers here:
Correct way to losslessly convert to and from std::string and QByteArray
(3 answers)
Closed 3 years ago.
I'm new on protobuf and QTcpServer/Socket and I want to read my .proto data send by my client, but when i'm reading the data, the QString done is empty
For now, I just want to send a message that say "hello" when my client is connected. The QByteArray returning by QTcpSocket::readAll is NOT empty, but the QString created with the bytes is empty.
Here is my .proto ultra basic one :
syntax = "proto3";
package protobuf;
message Message
{
string content = 2;
}
write functions :
// When i'm connecting to the server i create a PlayerManager and i call this function with message = "hello"
void Server::sendMessageToPlayer(const PlayerManager& playerManager, const QString& message)
{
auto messageProto = new protobuf::Message;
messageProto->set_content(message.toStdString());
playerManager.socketManager()->sendData(*messageProto);
}
// I serialize the protobuf
template <typename protobufType>
void sendData(const protobufType& protobuf)
{
std::string dataToSend;
if (!protobuf.SerializeToString(&dataToSend))
{
// This never pass -> the protobuf is well serialize
qDebug() << "The protobuf send cannot be serialized, please, make sure that you used protobufs correctly";
}
// Before i write it
write(dataToSend);
}
void SocketManager::write(const std::string& data)
{
// I tried this but it's not working either
// QTextCodec* codec = QTextCodec::codecForName("CP1251");
// QString codecData = codec->toUnicode(data.c_str());
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_10);
out << data.c_str();
_tcpSocket->write(block);
qDebug() << block;
}
read functions :
void SocketManager::read()
{
QByteArray bytes = _tcpSocket->readAll();
qDebug() << bytes;
// Doesn't work either
// QTextCodec* codec = QTextCodec::codecForName("CP1251");
// QString data = codec->toUnicode(bytes);
QString data(bytes);
qDebug() << data;
emitMessageType(data.toStdString());
}
void SocketManager::emitMessageType(const std::string& data)
{
// Protobufs can parse an empty string (and so, emit signal), to avoid that, the function will tell you if data
// are empty, then return
if (data.empty())
{
qDebug() << "Datas are empty";
return;
}
protobuf::Message message;
if (message.ParseFromString(data))
{
emit messageProtoReceived(message);
return;
}
qDebug() << "The data send cannot be translate, please, make sure that you used protobufs correctly";
}
So, I would like that my client receive "hello" when he is connected but my debug are :
Server side :
"\x00\x00\x00\b\x12\x05hello\x00"
Client side
"\x00\x00\x00\b\x12\x05hello\x00"
""
Datas are empty
When I use QTextCodec (commented lines of the code) the debug are :
Server side :
"\x00\x00\x00\x0E\x00\x12\x00\x05\x00h\x00""e\x00l\x00l\x00o"
Client side
"\x00\x00\x00\x0E\x00\x12\x00\x05\x00h\x00""e\x00l\x00l\x00o"
"\u0000\u0000\u0000\u000E\u0000\u0012\u0000\u0005\u0000h\u0000e\u0000l\u0000l\u0000o"
The data send cannot be translate, please, make sure that you used protobufs correctly
So the QByteArea is parse, but protobuf don't succeed to parse the given string.
Thanks for reading, I hope youc ould help me
Not sure if it's the case but the documentation says that the default constructor of a QString that takes a QByteArray:
The given byte array is converted to Unicode using fromUtf8(). Stops copying at the first 0 character, otherwise copies the entire byte array.
So probably, you are having some troubles whit the conversion.
As alternative, you can try ParseFromArray method, instead of converting a QByteArray into a std::string.
const auto byteArray = _tcpSocket->readAll();
protobuf::Message message;
if (!message.ParseFromArray(byteArray.data(), byteArray.size())) {
qDebug() << "Failed to parse person.pb.";
}
out << data.c_str() inside SocketManager::write might discard at first \0. Try converting to QByteArray as described at Correct way to losslessly convert to and from std::string and QByteArray to ensure the whole string is sent.
Hi everybody, first of all I'm new on network programming so maybe this is a simple question, but I don't get it. I try to send 6 Bytes to a microcontroller using tcp socket. In order to serialize my data I'm using qdatastream and qbytearray. That's the way I try to do this:
QByteArray buffer;
QDataStream outputStream(&buffer, QIODevice::WriteOnly);
outputStream.setVersion(QDataStream::Qt_5_8);
outputStream << (quint8) 0
<< (quint8) dataMessage.prefix
<< (quint8) dataMessage.paramID
<< (quint32) dataMessage.data;
outputStream.device()->seek(0);
outputStream << (quint8)(buffer.size() - sizeof(quint8));
qDebug() << buffer;
qDebug() << quint32(dataMessage.data);
sock->write(buffer);
if(sock->write(buffer) == -1)
{
return -1;
}
sock->flush();
My struct dataMessage looks like this for example: dataMessage={15,1,9400000}
Well in my buffer I would expect this Byte sequence "\x06\xF0\x01\x00\x8F\6E\xC0"
but I always get the following Output "\x06\xF0\x01\x00\x8Fn\xC0".
What am I doing wrong?
Overview of problem:
OS : Ubuntu
I am using qt utility to receive video data from remote machine( remote machine is using gstreamer to send live data) and write that data to port say 5000.
Port 5000 is already bind to another gstreamer utility. this utility listen to port 5000 and convert data into video streaming. Obviously things are not exactly working and I cant view video. So I have two questions:
1) With Qt utility , is it legal to write to port 5000 although port is bind to gstreamer utility.
2) I am using 3rd party library and its api to receive data from external source. The data get stored in array of characters. If I convert that into qbytearray then qbytearray has same size as char buffer. example
rc = zco_receive_source(sdr, &reader, bytesToRead, buffer); // this is 3rd part function
qDebug() << " copy buffer size =" << rc; // genrally this size is 1412
QByteArray msgRecvd;
msgRecvd = QByteArray(reinterpret_cast<char*>(buffer), rc);
if(! msgRecvd.isEmpty() )
{
qDebug() << " size of msgRecv =" << msgRecvd.size();// again 1412
udpSock->writeDatagram( msgRecvd, QHostAddress::LocalHost, 5000 );
}
But if I use QDataStream then QbyteArray got 4 extra bytes. code shown below
rc = zco_receive_source(sdr, &reader, bytesToRead, buffer); // this is 3rd part function
qDebug() << " copy buffer size =" << rc; // genrally this size is 1412
QByteArray msgRecvd;
QDataStream dataStream( &msgRecvd, QIODevice::WriteOnly );
dataStream.writeBytes( ( const char* )buffer, rc );
if(! msgRecvd.isEmpty() )
{
qDebug() << " size of msgRecv =" << msgRecvd.size();// got 4 extra bytes .. size is 1415. why ???
udpSock->writeDatagram( msgRecvd, QHostAddress::LocalHost, 5000 );
}
I want to know why QbyteArray got extra character and do I need to serialise data to forward it to port 5000?
Answering on second question:
Try QDataStream::writeRawData().
Form Qt docs:
QDataStream & QDataStream::writeBytes(const char * s, uint len)
Writes the length specifier len and the buffer s to the stream and returns a reference to the stream.
The len is serialized as a quint32, followed by len bytes from s. Note that the data is not encoded.
I am writing a program to send images captured from an OpenCV window over a TCP connection, using Qt libraries to setup the connections etc.
I have to functions (below) which are both working to send either text or a byte array. The problem I have is at the other end how can I tell if the data coming in is plain text, or an array containing an image. Is there an inbuilt way to do this, or do I need to put a byte at the start of the data to tell the receiver what data is coming? I already put the array length at the start of the serialized image data.
void Screenshot_controller::sendText(std::string textToSend)
{
if(connectionMade)
{
std::string endLine = "\r\n";
textToSend = textToSend + endLine;
const char * textChar = textToSend.c_str();
sendSocket->write(textChar);
sendSocket->flush();
qDebug() << "Text Sent from Server";
}
}
void Screenshot_controller::sendData(QByteArray dataToSend)
{
if(connectionMade)
{
sendSocket->write(dataToSend);
sendSocket->flush();
qDebug() << "Data Sent from Server";
}
}
You need to define the protocol yourself, whether that's with a byte, string, JSON header or any other method. The Tcp socket will allow you to transfer the data, but doesn't care what that data is; it's up to you to handle that.
I would like to connect to a listening server and transmit some data. I looked at the examples available but they seem to have extra functions that do not seem very helpful to me (i.e. connect, fortune, etc.). This is the code I have so far:
QTcpSocket t;
t.connectToHost("127.0.0.1", 9000);
Assuming the server is listening and robust, what do I need to implement to send a data variable with datatype QByteArray?
very simple with QTcpSocket. Begin as you did...
void MainWindow::connectTcp()
{
QByteArray data; // <-- fill with data
_pSocket = new QTcpSocket( this ); // <-- needs to be a member variable: QTcpSocket * _pSocket;
connect( _pSocket, SIGNAL(readyRead()), SLOT(readTcpData()) );
_pSocket->connectToHost("127.0.0.1", 9000);
if( _pSocket->waitForConnected() ) {
_pSocket->write( data );
}
}
void MainWindow::readTcpData()
{
QByteArray data = pSocket->readAll();
}
Be aware, though, that for reading from the TcpSocket you may receive the data in more than one transmission, ie. when the server send you the string "123456" you may receive "123" and "456". It is your responsibility to check whether the transmission is complete. Unfortunately, this almost always results in your class being stateful: the class has to remember what transmission it is expecting, whether it has started already and if it's complete. So far, I haven't figured out an elegant way around that.
In my case I was reading xml data, and sometimes I would not get all in one packet.
Here is an elegant solution. WaitForReadyRead could also have a time out in it and
then some extra error checking in case that timeout is reached. In my case I should never
receive an incomplete xml, but if it did happen this would lock the thread up indefinetly
without the timeout:
while(!xml.atEnd()) {
QXmlStreamReader::TokenType t = xml.readNext();
if(xml.error()) {
if(xml.error() == QXmlStreamReader::PrematureEndOfDocumentError) {
cout << "reading extra data" << endl;
sock->waitForReadyRead();
xml.addData(sock->readAll());
cout << "extra data successful" << endl;
continue;
} else {
break;
}
}
...