I set up a QTcpServer to listen to a Shoutcast stream. The newConnection()-signal gets fired as it should:
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(handleClientComm()));
void IcecastServer::handleClientComm(){
QTcpSocket *clientConnection = tcpServer->nextPendingConnection();
qDebug() << clientConnection->write("HTTP/1.0 200 OK\r\n\r\n" ) << endl;
clientConnection->flush();
}
How do I send HTTP 200 ?
You must extract QTcpSocket object from QTcpServer with nextPendingConnection() call when the newConnection() signal was emitted. And then you must call writeData() on the extracted QTcpSocket object.
The key here is that Listening socket (QTcpServer) is only responsible for creating Connection Sockets (or QTcpSocket) each time a new client connects. And the QTcpSocket is responsible for the actual communication with a specific client.
Maybe you can be more specific what exactly does not work for you and what have you tried? It would also be nice if you could provide us with wireshark PCAP if something does not seem to work as expected?
Related
I have a need for a very simple server program which executes one of five different activities, based on client connections.
Since this is for a demo, I don't need any complex network handling, my intention was just to open up five server sockets (say 10001 thru 10005 inclusive) and simply await incoming connections.
Upon the server receiving an incoming connection on (for example) the first socket 10001, it would immediately accept and close the connection, then execute the first action. Ditto for the other sockets. That way, I could demo the actions from another window simply by executing:
telnet 127.0.0.1 10001
Normally, I would use select() with a very short timeout value (i.e., not too onerous on the event processing thread) to await and detect which port was being connected to but, since this is a Qt application, I'm not sure that will work so well with the Qt event model.
What would be the best way of doing this with Qt (5.5, if it matters)? Is the use of a small-timeout select() actually going to work or do I need to go heavyweight with five separate QTcpServer objects, each with their own infrastructure (callbacks and such)?
If I properly understand, you want handle all requests in one place. In Qt you can use signal/slot for it. Connect signals from all QTcpServer objects to one slot, something like:
// Method to fully start a server on specific port.
QTcpServer *MyClass::StartServer(int port) {
QTcpServer *server = new QTcpServer();
server->listen(QHostAddress::Any, port);
connect(server, SIGNAL(newConnection()), this, SLOT(HandleConn()));
return server;
}
// Method to start all servers, serverArr is an array of QTcpServer
// items (in the object, obviously).
void MyClass::StartAllServers() {
for (size_t i = 0; i < sizeof(serverArr) / sizeof(*serverArr); i++)
serverArr[i] = StartServer(10000 + i);
}
// Callback to handle connections.
void MyClass::HandleConn() {
// This will call doAction with parameter based on which QTcpServer
// has caused the callback.
QTcpServer *source = static_cast<QTcpServer*>(sender());
for (size_t i = 0; i < sizeof(serverArr) / sizeof(*serverArr); i++)
if (source == serverArr[i])
doAction(i);
// Action done, so just accept and close connection.
QTcpSocket *socket = source->nextPendingConnection();
socket->close();
}
I have two programs doing IPC using QLocalSocket & QLocalServer, I have managed to implement the connection and send the data successfully.
However, for the QLocalServer side, how can I know a connection is ended by client (like the client program quit.)?
So that I could release the resource of corresponding socket on server side?
You can connect the void QLocalSocket::disconnected() signal from QLocalHost to a slot in your class:
connect(mySocket, &QLocalSocket::disconnected, this, &MyClass::socketDisconnected, Qt::QueuedConnection);
Or you can connect to the stateChange (for more detailed version), something like:
// Connect like this
connect(mySocket, &QLocalSocket::stateChanged, this, &MyClass::socketNewState, Qt::QueuedConnection);
// Implement a slot that handles the various states...
MyClass::socketNewState(QLocalSocket::LocalSocketState socketState)
{
qDebug() << "New state is " << socketState << endl;
}
I have compiled Qt's Trip Planner example that uses QTcpSocket and QTcpServer to create a client and server.
The problem is, the server's incomingConnection() slot is not being called. Even though the client connects to the server successfully. Therefore, the socket's readyRead() signal is never emitted and the client gets no data back.
tripserver.cpp
TripServer::TripServer(QObject *parent)
: QTcpServer(parent)
{
}
void TripServer::incomingConnection(int socketId)
{
qDebug() << "Incoming Connection";
ClientSocket *socket = new ClientSocket(this);
socket->setSocketDescriptor(socketId);
}
If I add a newConnection() slot, it gets called. So what is going on?
Found my answer.
The parameter list has changed since Qt 4.8.1
http://qt-project.org/doc/qt-5.0/qtnetwork/qtcpserver.html#incomingConnection
void TripServer::incomingConnection(qintptr socketId){}
I'm using Qt and trying to create a Client - Server connection. Whenever I click a button in my client application, a socket connects to the server and sends some data. The problem is I don't know how to receive the data. These are the slots for my buttons.
void MainWindow::func_button_one(){
socket->connectToHost("127.0.0.1", 1324);
if(socket->waitForConnected(1000)) {
socket->write("button one has been pressed");
socket->waitForBytesWritten(1000);
}
else {
qDebug() << "Something terrible seems to have happened.";
}
}
Now, in my server application, I tried something like this.
void MainWindow::newConnection(){
QTcpSocket *socket = server->nextPendingConnection();
socket->waitForReadyRead(1000);
qDebug() << "connection received";
qDebug() << socket->readAll();
socket->close();
}
The connection is all right, because the "connection received" message shows up. So, how am I supposed to receive the data from the client? QTcpServer doesn't have any read() function.
The connection is all right, because waitForReadyRead returned 'true', or the connection is not all right, because waitForReadyRead returned false after 1000ms. How would you know the difference?
Better work asynchronously with signals. Connect your socket to 'readyRead()'. Or at least test the return value of waitForReadyRead.
What would I need to receive data from a client?
QTcpServer Server;
if(!Server.listen("127.0.0.1", 9000)) {
return;
}
connect(Server, SIGNAL(newConnection()), this, SLOT(ReceiveData()));
Is this correct so far? What do I need in ReceiveData? Do I really need another function to receive the data? I would like to save it in a QByteArray
Thanks
As this hasn't been answered, here's a really basic example.
In your ReceiveData slot, you would need to accept the connection from the server.
In Qt's QTcpServer this is done by calling nextPendingConnection().
So the QTcpServer's newConnection slot will call your ReceiveData slot.
In your receivedata slot, you can do something like:
void ReceiveData()
{
QTcpSocket *socket = server->nextPendingConnection();
if (!socket)
return;
qDebug("Client connected");
socket->waitForReadyRead(5000);
QByteArray data = socket->readAll();
qDebug(data.constData());
socket->close();
}
Note: This is a blocking example, the waitForReadyRead will hang the thread for up to 5000 milliseconds.
To do a non blocking example, you need to connect another slot to the new socket's readyread signal.
Have you seen this example:
http://doc.qt.io/qt-5/qtnetwork-fortuneserver-server-cpp.html
PS:
Yes, you need at least one callback function to:
1) accept new connections
2) Receive and Send data on the connect(s)