Browser Connection Reset when using TCPServerwith Qt - c++

I want to create a Server for MJPEGs and I found this tutorial: http://www.bogotobogo.com/Qt/Qt5_QTcpServer_Client_Server.php. But when I connect from a Web Browser like Chrome (Microsoft Telnet works fine), it shows connection reset.
After creating the server, I would like to show MJPEGs on my browser (like an IP Camera does) using this: How to Create a HTTP MJPEG Streaming Server With QTcp-Server Sockets?
Here's my Server.cpp (A little modified) -
#include "stdafx.h"
#include "TCPServer.h"
TcpServer::TcpServer(QObject *parent) :
QObject(parent)
{
server = new QTcpServer(this);
connect(server, SIGNAL(newConnection()),
this, SLOT(newConnection()));
if (!server->listen(QHostAddress::Any, 9999))
qDebug() << "Server could not start";
else
qDebug() << "Server started!";
}
void TcpServer::newConnection()
{
QTcpSocket *socket = server->nextPendingConnection();
QByteArray header = "HTTP/1.1 200 OK\r\n";
socket->write(header);
QByteArray ContentType = "Content-Type: text/html\r\n";
socket->write(ContentType);
QByteArray Body = "Test";
socket->write(Body);
socket->flush();
socket->close();
}

After LOTS of trial and error (and luck), I found the solution. The code should end like this -
...
socket->flush();
socket->waitForBytesWritten(10000);
socket->close();
EDIT -
After trying again, I found out this - There should be an extra \r\n after the headers. So this will work -
void TcpServer::newConnection()
{
QTcpSocket *socket = server->nextPendingConnection();
QByteArray header = "HTTP/1.1 200 OK\r\n";
socket->write(header);
QByteArray ContentType = "Content-Type: text/html\r\n\r\n\*Here is the edit*\";
socket->write(ContentType);
QByteArray Body = "Test";
socket->write(Body);
socket->flush();
socket->close();
}

Related

QNetworkReply::NetworkError(ProtocolInvalidOperationError) what is it and how to fix it?

I'm attempting to make a POST request to a web page but I got a error in code below:
void WebViewModel::sendPOST(QString url)
{
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/x-www-form-urlencoded"));
QByteArray postData;
postData.append("");
manager_->post(request, postData);
connect(manager_, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinishedSlot(QNetworkReply *)));
}
void WebViewModel::replyFinishedSlot(QNetworkReply *reply)
{
QUrl webReportsUrl("http://...");
if(reply->error()) <-- **Here I got NetworkReply::NetworkError(ProtocolInvalidOperationError)**
{
qDebug() << "Error: ";
qDebug() << reply->errorString();
qDebug() << QNetworkReply::NetworkError(reply->error());
qDebug() << reply->error();
}
else
{
qDebug() << "no error";
}
reply->deleteLater();
}
This is 302 error with a following description from QT documentation:
the requested operation is invalid for this protocol
How to fix?
This happens when server responds with 400 status code (Bad Request) or with 418 status code (I'm a teapot).
Either server is not configured properly, or it does not expect post requests to that endpoint, or it doesn't like requests with empty body.
You can use curl to validate that server responds with no error to post requests.

How to read complete data using QTcpSocket (Qt4.7)

I created a TcpServer in order to receive data from a client. The client sends a lot of messages and I would like to read them. So far my TcpServer.cpp looks like this :
void TcpServer::serverStart()
{
server = new QTcpServer(this);
if (!server->listen(QHostAddress("192.168.x.x"), 48583))
{
qDebug() << "Not listening";
server->close();
delete server;
return;
}
else {
qDebug() << "Listening";
}
connect(server, SIGNAL(newConnection()), this, SLOT(newConnection()));
}
void TcpServer::newConnection()
{
socket = server->nextPendingConnection();
qDebug() << "Client connected";
connect(socket, SIGNAL(readyRead()), this, SLOT(getData()));
connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
}
void TcpServer::getData()
{
QByteArray buffer;
while (socket->bytesAvailable())
{
buffer.append(socket->readAll());
}
qDebug() << buffer;
}
void TcpServer::serverStop()
{
server->close();
delete server;
}
I know my getData function needs a lot more in order to receive everything but I don't understand the steps needed to do that.If someone could give me some pointers I would be grateful !
TCP is a transport protocol which is stream oriented. Imagine it as being a continuous flow of data. There are no messages defined by TCP yet, because once again it is a continuous flow of data.
I'm taking from your comment that you are not using any application layer protocol. You need an application layer protocol, like e.g. http, which is then defining "messages" and giving you further instructions on how to read a complete message.

Cant transfer QVector<double> between server and client using QTcpSocket and QDataStream

I have server and client app on my local computer and I wanna transfer small double vector between them.
Ive tried to do tihs on server:
if (socket != nullptr)
{
QByteArray data;
QDataStream out(data);
out.setDevice(socket);
out << 1.6;
socket->write(data);
socket->flush();
}
and this on client:
double a = -2.;
if (socket != nullptr)
{
socket->readAll();
in.setDevice(socket);
in >> a;
}
and i get 0 on client side instead of 1.6
For this task Server should looks like this:
Server.h
Server.cpp
And client should be looking like this:
Client.h
Client.cpp

Bad Request, Your browser sent a request that this server could not understand - Qt Websocket Server

I have two questions about this issue.
First of all I'm trying to get the following code working
socket = new QTcpSocket(this);
// I'm a little confused as to why we're connecting on port 80
// when my goal is to listen just on port 3000. Shouldn't I just
// need to connect straight to port 3000?
socket->connectToHost("localhost", 80);
if (socket->waitForConnected(3000))
{
qDebug() << "Connected!";
// send
socket->write("hello server\r\n\r\n\r\n\r\n");
socket->waitForBytesWritten(1000);
socket->waitForReadyRead(3000);
qDebug() << "Reading: " << socket->bytesAvailable();
qDebug() << socket->readAll();
socket->close();
}
else
{
qDebug() << "Not connected!";
}
But this is the error that I get:
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>400 Bad Request</title>\n</head><body>\n<h1>Bad `Request</h1>\n<p>Your browser sent a request that this server could not understand.<br />\n</p>\n<hr>\n<address>Apache/2.4.18 (Ubuntu) Server at 127.0.1.1 Port 80</address>\n</body></html>\n"`
Has anyone got any ideas about this?
Second question is: I'm trying to get a c++/Qt server working similar to a node js server. So I'm wanting to be able to access the connection requests in the browser. So when someone connects to site:3000 I will be able to catch the request and display some content. Can it be achieved with a QTcpSocket server? If so then how could I implement something like :
// I know this isn't valid c++, Just to give an idea of what I'm trying to achieve
socket.on(Request $request) {
if ($request.method() == 'GET') {
}
}
If this is achievable is there much speed gains in comparison to doing this in nodejs?
I'm personally trying to avoid js as much as possible.
if i comment the code then I can get a running program but when I try to connect on port 8000 from the browser nothing happens (just a 404 error)
updated answer:
header file:
#ifndef SOCKETTEST_H
#define SOCKETTEST_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
class SocketTest : public QTcpServer
{
public:
SocketTest(QObject *parent);
private:
QTcpSocket *client;
public slots:
void startServer(int port);
void readyToRead(void);
void incomingConnection(int socket);
};
#endif // SOCKETTEST_H
.cpp file
#include "sockettest.h"
SocketTest::SocketTest(QObject *parent) :
QTcpServer(parent)
{
this->startServer(8000);
}
void SocketTest::startServer(int port)
{
bool success = listen(QHostAddress::Any, port); // this starts the server listening on your port
// handle errors
}
void SocketTest::incomingConnection(int socket)
{
// a client has made a connection to your server
QTcpSocket *client = new QTcpSocket(this);
//client->setSocketDescription(socket);
// these two lines are important, they will direct traffic from the client
// socket to your handlers in this object
connect(client, SIGNAL(readyRead()), this, SLOT(readToRead()));
connect(client, SIGNAL(disconnect()), this, SLOT(disconnected()));
}
void SocketTest::readyToRead(void)
{
QTcpSocket *client = (QTcpSocket*)sender();
qDebug() << "Just got a connection";
// you can process requests differently here. this example
// assumes that you have line breaks in text requests
while (client->canReadLine())
{
QString aLine = QString::fromUtf8(client->readLine()).trimmed();
// Process your request here, parse the text etc
}
}
// this gives me the following error
// /user_data/projects/qt/QtServer/sockettest.cpp:47: error: no ‘void
// SocketTest::disconnected()’ member function declared in class ‘SocketTest’
void SocketTest::disconnected()
^
void SocketTest::disconnected()
{
// jsut a qu, wont all these * vars lead to a memory leak? and shouldn't I be using a var Qtc... *client; in the header file?
QTcpSocket *client = (QTcpSocket*)sender();
// clean up a disconnected user
}
Here with waitForConnected, you are connecting on port 80, and waiting 3000ms maximum for the "connected state", i.e. not connecting on port 3000 at all. This is the blocking way of waiting for a connection to be established, instead of connecting to the QTcpSocket::connected signal.
Like Yuriy pointed out, QNetworkAccessManager is way more convenient to handle HTTP requests as a client. As in your example, you created a TCP client, and not a server
Yes you can build an web server with Qt, it's a bit painfull from scratch (QTcpServer class), but several projects make it a bit easier: QHttpServer, QtWebApp
If performance is your goal, I doubt you can achieve something significantly better (or just "better") without spending a lot of time on it. Namely to be able to handle a large number of request simultaneously in a fast way, a basic implementation will not be enough.
You should subclass QTCPServer. Set it up to listen on the port you want. This object will then get the requests and you can parse them and respond to them.
Something like this (partial code);
#include <QTcpServer>
#include <QTcpSocket>
class mySuperNodeLikeServer : public QTcpServer
{
mySuperNodeLikeServer(QObject *parent);
void startServer(int port);
void readyToRead(void);
void incomingConnection(int socket);
}
// in your .cpp file
void mySuperNodeLikeServer::startServer(int port)
{
bool success = listen(QHostAddress::Any, port); // this starts the server listening on your port
// handle errors
}
void mySuperNodeLikeServer::incomingConnection(int socket)
{
// a client has made a connection to your server
QTcpSocket *client = new QTcpSocket(this);
client->setSocketDescription(socket);
// these two lines are important, they will direct traffic from the client
// socket to your handlers in this object
connect(client, SIGNAL(readyRead()), this, SLOT(readToRead()));
connect(client, SIGNAL(disconnect()), this, SLOT(disconnected()));
}
void mySuperNodeLikeServer::readyToRead(void)
{
QTcpSocket *client = (QTcpSocket*)sender();
// you can process requests differently here. this example
// assumes that you have line breaks in text requests
while (client->canReadLine())
{
QString aLine = QString::fromUtf8(client->readLine()).trimmed();
// Process your request here, parse the text etc
}
}
void mySuperNodeLikeServer::disconnected()
{
QTcpSocket *client = (QTcpSocket*)sender();
// clean up a disconnected user
}

Error while using QTcpSocket

I am creating a (very basic) MJPG server to show webcam data on a browser. I have partly managed to do it so far.
Here is my code:
TcpServer::TcpServer(QObject *parent) :
QObject(parent)
{
server = new QTcpServer(this);
// whenever a user connects, it will emit signal
connect(server, SIGNAL(newConnection()),
this, SLOT(newConnection()));
if (!server->listen(QHostAddress::Any, 9999))
qDebug() << "Server could not start";
else
qDebug() << "Server started!";
}
...
void TcpServer::newConnection()
{
QTcpSocket *socket = server->nextPendingConnection();
QByteArray ContentType = ("HTTP/1.0 200 OK\r\n" \
"Cache-Control: no-cache\r\n" \
"Cache-Control: private\r\n" \
"Content-Type: multipart/x-mixed-replace;boundary=--boundary\r\n");
socket->write(ContentType);
std::vector<uchar> buff;
Mat img; //OpenCV Material
while (1) {
// Image to Byte Array via OPENCV Method
buff.clear();buff.empty();
vCapture->read(img); //Read from webcam
imencode(".jpg", img, buff, compression_params);
std::string content(buff.begin(), buff.end());
QByteArray CurrentImg(QByteArray::fromStdString(content));
QByteArray BoundaryString = ("--boundary\r\n" \
"Content-Type: image/jpeg\r\n" \
"Content-Length: ");
BoundaryString.append(QString::number(CurrentImg.length()));
BoundaryString.append("\r\n\r\n");
socket->write(BoundaryString);
socket->write(CurrentImg); // Write The Encoded Image
socket->flush();
}
}
The Problem -
When I run this program, the first image is shown. After that, the following error is continuously printed on the app -
QIODevice::write (QTcpSocket): device not open
It looked like the socket got closed, so I used re-initialized the socket, like this - socket = server->nextPendingConnection();, although the app threw an error with this code. Any help on how to fix this?
EDIT -
I tried the lambda method and it worked fine. However, I still face 2 problems -
The image size has to be excessively low (around 270x480 with lowest JPG quality)
(MORE IMPORTANT) I have to manually press the reload button on browser to reload the image, it doesn't automatically change from one image to the other.
It looked like the socket got closed
Rather than guessing, connect to the error signals of TCPServer and TCPSocket to know when errors occur, or when a client disconnects.
The problem you have is the while(1) loop. Qt is an event-driven framework, so having code in an infinite loop on the main thread is going to prevent events being delivered.
Instead of the infinite loop, connect to QTcpSocket::readyRead signal and handle the data when the connected slot is called.
Qt demonstrates this with the Fortune Server and Fortune Client example code.
If you're using C++ 11, you can use a connection to a lambda function to handle the readyRead, like this
void TcpServer::newConnection()
{
...
QTcpSocket *m_TcpHttpClient = server->nextPendingConnection();
connect(m_TcpHttpClient, &QTcpSocket::readyRead, [=](){
// handle received data here
});
}
Here Is the Code I used to open the MJPEG Streaming Server in my original Project. Perhaps It can help you finding out your Problem.
void MjpegStreamingEngine::StartServer(){
m_TcpHttpServer = new QTcpServer();
m_TcpHttpServer->connect(m_TcpHttpServer,
SIGNAL(newConnection()),
this,
SLOT(TcpHttpconnected()));
m_TcpHttpServer->listen(QHostAddress::Any,
8889);
}
void MjpegStreamingEngine::TcpHttpconnected(){
m_TcpHttpClient = m_TcpHttpServer->nextPendingConnection();
m_TcpHttpClient->connect(m_TcpHttpClient,
SIGNAL(readyRead()),
this,
SLOT(TcpHttpreadyRead()));
}
void MjpegStreamingEngine::TcpHttpreadyRead(){
m_TcpHttpClient->readAll(); // Discard "Get Request String"
QByteArray ContentType = ("HTTP/1.0 200 OK\r\n" \
"Server: en.code-bude.net example server\r\n" \
"Cache-Control: no-cache\r\n" \
"Cache-Control: private\r\n" \
"Content-Type: multipart/x-mixed-replace;boundary=--boundary\r\n\r\n");
m_TcpHttpClient->write(ContentType);
while(1){
if (m_TcpHttpClient->isOpen())
{
// Send Image
QThread::msleep(10);
}else{
return;
}
}
m_TcpHttpClient->disconnect(); //Should never be Reached
}