QTcpSocket Telnet readyRead returns rubbish - c++

i used realterm to telnet to the device and it works but when i try to use QTcpSocket to access it, i get rubbish data from the socket readAll(), whats wrong???
QObject::connect(&sock, SIGNAL(readyRead()), this, SLOT(readyRead()));
void QTelnet::readyRead()
{
QByteArray ba = sock.readAll();
qDebug() << "Read:" << ba ;
}
Output:
"ÿýÿý ÿý#ÿý'"
Update:
i only called the sock.connectToHost("192.168.80.17", 23);
nothing else
the expected output is as follows:
Linux 2.4.31 (NTP001) (26)
NTP001 login:

If you're sure the sent data is a valid string, try to convert them to one:
qDebug() << "Read:" << QString(ba);
Otherwise, the reason behind the "rubbish" may be as simple as that's just the data that the connecting client sent.

Related

toLocal8bit send over TCP

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);
...
}
...
}

Communication fails between Python 3 socket and QTcpsocket (c++)

Using Qt's QTcpsocket library and python 3's socket class currently. I have already gotten Qt's c++ fortune client / server example to build and run properly. However, it's for a client and server that are both C++. The requirement is that the server is running Python.
# Server.py
import socket
# ...
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("localhost", 45000)
sock.listen(1) # queuing up 1 request for now.
(clientsocket, address) = sock.accept() # waits until client connects.
chunk = clientsocket.recv(1024).decode() # client is now connect
print(chunk) #prints out message from client
msg = "Hello from the server"
msg = str.encode(msg)
# send the message back to the client
clientsocket.sendall(msg)
and
// Client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <QObject>
#include <QtNetwork/QtNetwork>
class Client : public QObject {
Q_OBJECT
public:
Client();
QTcpSocket *m_socket;
QHostAddress m_serverAddr = QHostAddress("127.0.0.1");
quint16 m_serverPort = 45000;
private:
QDataStream m_dataStream;
void testConnect();
};
#endif
and
// client.cpp
Client::Client() {
m_socket = new QTcpSocket(this);
m_dataStream.setDevice(m_socket);
m_dataStream.setVersion(QDataStream::Qt_4_0);
testConnect();
}
void Client::testConnect() {
m_socket->abort(); // if m_socket is not already connected, this does nothing
m_socket->connectToHost(m_serverAddr, m_serverPort);
if (m_socket->waitForConnected(30000)) {
qDebug() << "Connected to server...";
m_socket->write("Hello server from client"); // is received!
m_socket->waitForBytesWritten();
m_socket->waitForReadyRead();
qDebug() << "Reading: " << m_socket->bytesAvailable();
m_dataStream.startTransaction();
QString nextFortune;
m_dataStream >> nextFortune;
if (!m_dataStream.commitTransaction()) {
qDebug() << "Read errors have occurred."; // prints when connected to python server. not desired behavior
m_socket->close();
return;
}
// This prints when running the Qt fortune c++ server, but not the python server (above).
qDebug() << "No read errors occurred during read transactions.";
qDebug() << nextFortune;
}
}
What ends up happening is the server receives the message from the client without issue, but when the server attempts to send a reply with clientsocket.sendall(msg), m_dataStream.commitTransaction() returns false. My initial instinct was that the encoding was wrong on the python side. Does QDataStream require a special encoding?
Documentation for QDataStream::commitTransaction():
bool QDataStream::commitTransaction()
Completes a read transaction. Returns true if no read errors have occurred
during the transaction; otherwise returns false.
Also, after running, here is the output of the c++ client:
Connected to server...
Reading: 25
Read errors have occurred.
When you want to use QDataStream with operator >> you have to follow a serialization format. The call QDataStream.setVersion() select concrete format.
I've been able to found documentation only for version 12 (applies from QDataStream::Qt_4_6 to QDataStream::Qt_4_9) and version 13 (QDataStream::Qt_5_0).
Version 12 and 13 have the same format for serialization of the QString:
> If the string is null: 0xFFFFFFFF (quint32)
> Otherwise: The string length in bytes (quint32) followed by the data in UTF-16
When you call m_dataStream >> nextFortune it expects the incoming data will be in the format described above.
The code in Python for send encoded QString can look like this:
import struct
msg = "Hello from the server".encode("utf-16be")
clientsocket.sendall(struct.pack(">I", len(msg)) + msg)
str.encode("utf-16be") - encodes the string into UTF-16 with big-endian order
struct.pack(">I", len(msg)) - creates a 32-bit unsigned integer contains the length of the encoded string (I) in the big-endian orderd (>)
All data send to Qt's client are in big-endian order because it is implicit order which QDataStream uses.
I've tested the code with Qt 5.9 and serialization version QDataStream::Qt_4_0.

QT serial port not working

I'm trying to write \ read from a serial device using a usb / rs 232 cable.
I'm pretty sure that my code writes " #002s " (this is a control code) to the serial device, because
a) the serial port is open
b) the serial port is writable
c) the code successfully navigates "wait For Bytes Written (-1)"
d) when using a serial port sniffer the data is successfully written.
The issue I have is that I don't receive any data, and no data is being emitted from the other device. When using qt terminal writing the same " #002s " produces the correct response.
Any ideas?
many thanks.
#include "test_serial.h"
#include "ui_test_serial.h"
#include <QtSerialPort/QtSerialPort>
#include <QDebug>
QSerialPort *serial;
Test_Serial::Test_Serial(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Test_Serial)
{
ui->setupUi(this);
serial = new QSerialPort(this);
connect(serial,SIGNAL(readyRead()),this,SLOT(serialReceived()));
serial->setPortName("COM1");
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
serial->open(QIODevice::ReadWrite);
if (serial->isOpen() && serial->isWritable())
{
QByteArray input;
input = "#";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "0";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "0";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "2";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "s";
serial->write(input);
serial->waitForBytesWritten(-1);
input = "\r";
serial->write(input);
serial->waitForBytesWritten(-1);
serial->flush();
serial->waitForReadyRead(100);
QByteArray output = serial->readAll();
ui->label_2->setText(output);
}}
Test_Serial::~Test_Serial()
{
delete ui;
serial->close();
}
void Test_Serial::serialReceived()
{
QByteArray output;
output = serial->readAll();
ui->label->setText("output");
}
If you want to write " #002s ", Why not write at once? May be the serial device cant identify the control code when you write each character.
void Test_Serial::writeDataToSerialPort()
{
QByteArray input = QString("#002s").toLocal8Bit();
serial->write(input);
}
And no need for this reading part .
serial->waitForReadyRead(100);
QByteArray output = serial->readAll();
ui->label_2->setText(output);
The Test_Serial::serialReceived will be called any way when you have the response from the serial device.
And you can catch the error on opening the port by using the error signal from QSerialPort
connect(serial,SIGNAL(error(QSerialPort::SerialPortError)),this,SLOT(serialPortError(QSerialPort::SerialPortError)));
void Test_Serial::serialPortError(QSerialPort::SerialPortError error)
{
//Print error etc.
}
The issue ended up being that the readyread flag is only emitted if theirs data to read. However I was sending the data too quickly for the external device to receive it. This meant that some data was lost thus the device never recognised it as a valid command.
This meant that it was still waiting for the message to finish, hence the "IRP_MJ_DEVICE_CONTROL (IOCTL_SERIAL_WAIT_ON_MASK) UP STATUS_CANCELLED COM1" error message upon closing the program. This also explains why their were no error messages with regards to writing data.
This also explains why the same program occasionally managed to read data, and at other times failed, (even without rebuilding the program, just re-running it.) When the data was read, the processor was more loaded, i.e. programs running in the background. This meant that the data was transmitted more slowly and thus the external device could recognise the commands and thus reply.

How to write Client-Server application and implement simple protocol in Qt

Maybe this is stupid question, actually it's appeal, or Qt is just to complicated for me.
Here's the thing:
I'm used to java when writing client-server application, and it's very simple. I would like to do same things in C++ (I'm very familiar with C++ itself), and I choose to learn Qt. I tried to write some applications in qt, but with partial success.
First thing that bothers me is signals and slots. I know how to use them in GUI programming but it confuses me with networking. And there's problem with blocking. When I call BufferedReader's readLine() method in java it blocks until it receives line from socket connection. In Qt I must make sure that there is line available every time, and handle it when there isn't one.
And when I connect QSocket's error signal to some of my custom slots, the signal is emitted when server sends last line and closes the connection, and in client's slot/function that reads I never read that last line. That are some problems I faced so far.
Slots and checking if there is data available makes me confused when I had to implements even the simplest protocols.
Important part:
I tried to find good example on the internet, but problem is that all examples are to complicated an big. Is there anyone how can show me how to write simple client-server application. Server accepts only one client. Client sends textual line containing command. If command is "ADD" or "SUB", server sends "SUP" indicating that command is supported. Otherwise it sends "UNS" and closes the connection. If client receives "SUP" it sends to more lines containing numbers to be subtracted or added. Server responds with result and closes connection.
I know that C++ requires more coding, but in Java this would take only 5 minutes, so it shouldn't take to long to write it in C++ either.
I'm sure this example would be very valuable to anyone who wants to learn networking in Qt.
edit:
This is my try to make the application (described above):
here is the server part:
#ifndef TASK_H
#define TASK_H
#include <QObject>
#include <QTcpServer>
class Task : public QObject
{
Q_OBJECT
public:
Task(QObject *parent = 0) : QObject(parent) {}
public slots:
void run();
void on_newConnection();
void on_error(QAbstractSocket::SocketError);
signals:
void finished();
private:
QTcpServer server;
};
#endif // TASK_H
void Task::run()
{
connect(&server,SIGNAL(newConnection()),this,SLOT(on_newConnection()));
connect(&server,SIGNAL(acceptError(QAbstractSocket::SocketError)),this,SLOT(on_error(QAbstractSocket::SocketError)));
if(server.listen(QHostAddress::LocalHost, 9000)){
qDebug() << "listening";
}else{
qDebug() << "cannot listen";
qDebug() << server.errorString();
}
}
void Task::on_newConnection(){
std::cout << "handeling new connection...\n";
QTcpSocket* socket = server.nextPendingConnection();
QTextStream tstream(socket);
while(!socket->canReadLine()){
socket->waitForReadyRead((-1));
}
QString operation = tstream.readLine();
qDebug() << "dbg:" << operation;
if(operation != "ADD" && operation != "SUB"){
tstream << "UNS\n";
tstream.flush();
socket->disconnect();
return;
}
tstream << "SUP\n";
tstream.flush();
double op1,op2;
while(!socket->canReadLine()){
socket->waitForReadyRead((-1));
}
op1 = socket->readLine().trimmed().toDouble();
qDebug() << "op1:" << op1;
while(!socket->canReadLine()){
socket->waitForReadyRead(-1);
}
op2 = socket->readLine().trimmed().toDouble();
qDebug() << "op2:" << op2;
double r;
if(operation == "ADD"){
r = op1 + op2;
}else{
r = op1 - op2;
}
tstream << r << "\n";
tstream.flush();
qDebug() << "result is: " << r;
socket->disconnect();
}
void Task::on_error(QAbstractSocket::SocketError ){
qDebug() << "server error";
server.close();
}
This is client side (header is similar to server's so I wont post it):
void Task::run()
{
QTcpSocket socket;
std::string temp;
socket.connectToHost(QHostAddress::LocalHost,9000);
if(socket.waitForConnected(-1))
qDebug() << "connected";
else {
qDebug() << "cannot connect";
return;
}
QTextStream tstream(&socket);
QString op;
std::cout << "operation: ";
std::cin >> temp;
op = temp.c_str();
tstream << op << "\n";
tstream.flush();
qDebug() << "dbg:" << op << "\n";
while(!socket.canReadLine()){
socket.waitForReadyRead(-1);
}
QString response = tstream.readLine();
qDebug() << "dbg:" << response;
if(response == "SUP"){
std::cout << "operand 1: ";
std::cin >> temp;
op = temp.c_str();
tstream << op + "\n";
std::cout << "operand 2: ";
std::cin >> temp;
op = temp.c_str();
tstream << op + "\n";
tstream.flush();
while(!socket.canReadLine()){
socket.waitForReadyRead(-1);
}
QString result = tstream.readLine();
std::cout << qPrintable("result is: " + result);
}else if(response == "UNS"){
std::cout << "unsupported operatoion.";
}else{
std::cout << "unknown error.";
}
emit finished();
}
What I could do better?
What are some good practices in similar situations?
When using blocking (not signal/slot mechanism), what is the best way to handle event when other side closes the connection?
Can someone rewrite this to make it look more professional (I just what to see how it supposed to look like, because I think that my solution is far from perfect) ?
Can someone rewrite this using signals and slots?
Thanks you.
Sorry for my English, and probably stupidity :)
Networking with Qt is not that difficult.
Communication between two points is handled by a single class; in the case of TCP/IP, that would be the QTcpSocket class. Both the client and server will communicate with a QTcpSocket object.
The only difference with the server is that you start with a QTcpServer object and call listen() to await a connection...
QTcpServer* m_pTcpServer = new QTcpServer
//create the address that the server will listen on
QHostAddress addr(QHostAddress::LocalHost); // assuming local host (127.0.0.1)
// start listening
bool bListening = m_pServer->listen(addr, _PORT); //_PORT defined as whatever port you want to use
When the server receives a connection from a client QTcpSocket, it will notify you with a newConnection signal, so assuming you've made a connection to a socket in your own class to receive that signal, we can get the server QTcpSocket object to communicate with the client...
QTcpSocket* pServerSocket = m_pServer->nextPendingConnection();
The server will receive a QTcpSocket object for each connection made. The server socket can now be used to send data to a client socket, using the a write method...
pServerSocket->write("Hello!");
When a socket (either client or server) receives data, it emits the readyRead signal. So, assuming you have made a connection to the readyRead signal for the socket, a slot function can retrieve the data...
QString msg = pSocket->readAll();
The other code you'll need is to handle the connect, disconnect and error signals, which you should connect relevant slots for receiving these notifications.
Ensure you only send data when you know the connection has been made. Normally, I would have the server receive a connection and send a 'hello' message back to the client. Once the client receives the message, it knows it can send to the server.
When either side disconnects, the remaining side will receive the disconnect signal and can act appropriately.
As for the client, it will just have one QTcpSocket object and after calling connectToHost, you will either receive a connected signal if the connection was succesfully made, or the error signal.
Finally, you can use QLocalServer and QLocalSocket in the same way, if you're just trying to communicate between processes on the same machine.

Qt Serial Port communication

I am writing a Qt application to communicate with another computer over a serial port. I have 2 real issues.
1.
I can send and receive data fine, but sometimes the serial port "eats" part of my input.
For example if I send:
cd /application/bin
sometimes (not always) it will only receive:
cd /applica
(Since it's a terminal it echoes the input back. Also my prompt tells me I'm clearly in the wrong spot.)
2.
Also, sometimes the Qt slot which fires when there is data available doesn't fire even though I know that there's data I can receive. If I send another \r\n down the port the slot will fire.
For example sometimes I'll ls something, and the command name will be read back from the port, but the contents of the folder sit there in limbo until I hit return again. Then I get the listing of the directory and two prompts.
Here's my code:
void Logic::onReadyRead(){
QByteArray incomingData;
incomingData = port->readAll();
QString s(incomingData);
emit dataAvailable(s);// this is a Qt slot if you don't know what it is.
qDebug() << "in:"<< s.toLatin1();
}
void Logic::writeToTerminal(QString string )
{
string.append( "\r\n");
port->write((char*)string.data(), string.length());
if ( port->bytesToWrite() > 0){
port->flush();
}
qDebug() << "out:" << string.toLatin1();
}
I found the solution, and I suspect it was an encoding error, but I'm not sure. Instead of sending a QString down the serial port, sending a QByteArray fixed both problems. I changed the writeToTerminal() method:
void Logic::writeToTerminal(QString string )
{
string.append( "\r");
QByteArray ba = string.toAscii();
port->write(ba);
}
From this forum, it appears that sometimes not all the data gets sent, and whatever does gets sent has a '\0' appended to it. So if
cd /applica'\0'
got sent, then the port->readAll() would stop there, because it thinks it has read everything.
One suggested answer on that forum was to read line by line, which your code almost does. So I think in your case, you can change your code to:
void Logic::onReadyRead(){
QByteArray incomingData;
if(port->canReadLine()) {
incomingData = port->readLine();
QString s(incomingData);
emit dataAvailable(s);// this is a Qt slot if you don't know what it is.
qDebug() << "in:"<< s.toLatin1();
}
}
void Logic::writeToTerminal(QString string )
{
string.append( "\r\n");
port->write((char*)string.data(), string.length());
if ( port->bytesToWrite() > 0){
port->flush();
}
qDebug() << "out:" << string.toLatin1();
}