Qt unix domain socket server side reading - qt

I am using Qt for unix domain socket and I have a question:
I want the server side read the message sent from the client side right after the connection established, below are my codes
if (!server->listen("mySocket2")) {
//lisetn for new connection
close();
return;
}
connect(server, &QLocalServer::newConnection, this, &MainWindow::readData);
And in the readData function
QLocalSocket *clientConnection = server->nextPendingConnection();
connect(clientConnection, &QLocalSocket::disconnected,
clientConnection, &QLocalSocket::deleteLater);
connect(clientConnection,&QLocalSocket::readyRead,
this,&MainWindow::readyReadData);
In the readyReadData function
QByteArray block;
block=clientConnection->readAll();
qDebug()<<block;
clientConnection->disconnectFromServer();
but the app always crashed, can you plz advise me on that?

I don't see any condition handling for when there are no pending connections. This case will cause nextPendingConnection() to return a nullptr (actually, just a zero), which may or may not cause the signal/slot connections to fail.

Related

Qt: Detect a QTcpSocket disconnection in a console app when the user closes it

My question title should be enough. I already tried (without success):
Using a C-style destructor in a function: __attribute__((destructor)):
void sendToServerAtExit() __attribute__((destructor)) {
mySocket->write("$%BYE_CODE%$");
}
The application destructor is called, but the socket is already disconnected and I can't write to the server.
Using the standard C function atexit(), but the TCP connection is already lost so I can't send anything to the server.
atexit(sendToServerAtExit); // is the same function of point 1
The solution I found is check every second if all connected sockets are still connected, but I don't want to do so inefficient thing. It's only a temporary solution. Also, I want that others apps (even web ones) can join the chat room of my console app, and I don't want to request data every second.
What should I do?
Handle the below signal (QTcpSocket is inherited from QAbstractSocket)
void QAbstractSocket::stateChanged(QAbstractSocket::SocketState socketState)
Inside the slot called, check if socketState is QAbstractSocket::ClosingState.
QAbstractSocket::ClosingState indicates the socket is about to close.
http://doc.qt.io/qt-5/qabstractsocket.html#SocketState-enum
You can connect a slot to the disconnect signal.
connect(m_socket, &QTcpSocket::disconnected, this, &Class::clientDisconnected);
Check the documentation.
You can also know which user has been disconnected using a slot like this:
void Class::clientDisconnected
{
QTcpSocket* client = qobject_cast<QTcpSocket*>(sender());
if(client)
{
// Do something
client->deleteLater();
}
else
{
// Handle error
}
}
This method is usefull if you have a connections pool. You can use it as well if you have a single connection, but do not forget nullptr after client->deleteLater().
If I understand you question correctly, you want to send data over TCP to notify the remote computer that you are closing the socket.
Technically this can be done in Qt by listenning to the QIODevice::aboutToClose() or QAbstractSocket::stateChanged() signals.
However, if you graciously exit your program and close the QTcpSocket by sending a FIN packet to the remote computer. This means that on the remote computer,
the running program will be notified that the TCP connection finished. For instance, if the remote program is also using QTcpSocket, the QAbstractSocket::disconnected()
signal will be emitted.
The real issues arise when one of the program does not graciously exit (crash, hardware issue, cable unplugged, etc.). In this case, the TCP FIN packet will
not be sent and the remote computer will never get notified that the other side of the TCP connection is disconnected. The TCP connection will just time-out after a few minutes.
However, in this case you cannot send your final piece of data to the server either.
In the end the only solution is to send a "I am here" packet every now and then. Even though you claim it is ineficient, it is a widely used technique and it also has the advantage that it works.

QTcpSocket KeepAliveOption on server side

I would like to set QTcpSocket::KeepAliveOption on the server side, so that the connection gets automatically disconnected when the network connection is lost for some time.
However, the documentation says:
On Windows Runtime, QAbstractSocket::KeepAliveOption must be set before the socket is connected.
On a client, you would just create the socket, set the option, then connect it.
On the server side, you do not create the sockets, they are created and returned buy QTcpServer::nextPendingConnection(). These are already connected.
So am I basically stuck, and is the only viable option to implement "heartbeats" myself?
EDIT
I have created a QTcpServer subclass as suggested by talamaki for setting the flag on incoming connection sockets:
class CustomTcpServer : public QTcpServer
{
Q_OBJECT
public:
CustomTcpServer(QObject * parent = 0) : QTcpServer(parent) { }
void incomingConnection(qintptr socketDescriptor)
{
QTcpSocket *socket = new QTcpSocket(this);
socket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
socket->setSocketDescriptor(socketDescriptor);
addPendingConnection(socket);
}
};
Then, i have set
\HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\TCPIP\Parameters\KeepAliveTime
To a DWORD value of 30000 (thirty seconds)
And rebooted the system to be sure it is used by the system
But, I still get no disconnected signal after several minutes, after having unplugged the ethernet cable of the remote client.
How to make the KeepAlive feature work?
Thanks
You should be able override QTcpServer::incomingConnection and create QTcpSocket yourself instead of letting the framework do it.
On Windows, AFAIK there are three parameters that govern the timeout of a TCP connection. You have set the KeepAliveTime, which is the time until an idle connection will be starting to send keep-alive segments (the connection must be idle, no segments have been sent, no Acks received). Then there is the number of keep-alives that need to be unanswered to determine that it is dead, which is TcpMaxDataRetransmissions. Finally, the is the time between the keep-alive segments which is KeepAliveInterval. Check with Wireshark, if empty TCP segments are being sent (which are the Keep-Alives). Some versions of Windows might misbehave, too and ignore some of the settings.
Usually Servers re-starts the Listenning after a elapsed time without traffic. After close en re-open , new connections will arrive.
ALSO Client and Server can specify a test protocol like PING - PONG message on interval of X seconds, minutes, etc
In server side, when missing pings after X seconds, maybe indicate to restart the server.
Best regards!

recvfrom does not receive anything from the client, but the client is sending the info

So I wanted to make sure I am not missing something and I have the concepts clean in my head.
This is the part of the code I have:
UDP_Msg mensajeRecibidoUdp;
struct sockaddr_in c_ain;
sock_udp=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in c_ain;
socklen_t tam_dir;
while(1)
{
if(recvfrom(sock_udp, &mensajeRecibidoUdp, sizeof(UDP_Msg), 0,
(struct sockaddr*) &c_ain, &tam_dir) <0)
....
The problem is that it waits for a message to arrive. And the message is sent, but this code does not get anything, it doesn't unfreeze.
It's a simple exercise, and the client is already built. It gets the port from a file, then sends a UDP_Message that is a struct with a couple ints and an array (the client already knows the IP and port).
I thought the way I handle the buffer could be wrong, but every example I've seen uses it like that. I also thought that the c_ain variable might needed to be initialized, but that's not the case if I understand it properly. So I don't get why the process gets... blocked, not sure what's the proper word, and since a lot of time passes by, an alarm goes off and the process gets killed (because it should have got info and keep with the code but it did not).
I can add lots of other info, I tried to keep it short. I kind of know that call is the one that isn't working properly because of how it behaves when I run the client-server thingy.
Edit: Bind:
bzero((char*)&dir_udp_serv,sizeof(struct sockaddr_in));
dir_udp_serv.sin_family=AF_INET;
dir_udp_serv.sin_addr.s_addr=inet_addr(HOST_SERVIDOR);
dir_udp_serv.sin_port=0;
fprintf(stderr,"SERVIDOR: Asignacion del puerto servidor: ");
if(bind(sock_udp,
(struct sockaddr*)&dir_udp_serv,
sizeof(struct sockaddr_in))<0)
{
fprintf(stderr,"ERROR\n");
close(sock_udp); exit(1);
}
Second edit: I just realized I have two binds in the code. The idea is I create two connections on the same server, one for UDP and one for TCP. So I made the same steps for both UDP and TCP. From the answer I got I realize that might be wrong. Would it be only 1 bind per socket, even if I create two sockets, one for UDp and one for TCP?
The above does not seem to be the case.
Also, I don't know what more details should I add, but the server and client are both on the same computer so their address are both 127.0.0.1, but that's expected and I believe does not change anything as to why the server does not get the info sent from the client.
Ask yourself: on which port do your clients send their messages? Where is that port in your server code? Nowhere. You forgot to bind your local socket to your local address (and port) :
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_addr.s_addr = inet_addr("0.0.0.0");
local.sin_port = htons(PORT); // Now the server will listen on PORT.
if(bind(sock_udp, (struct sockaddr*)&local, sizeof(local)) < 0){
perror("bind");
exit(1);
}
// Now you may call recvfrom on your socket : your server is truly listening.
Note that you only need to bind once. No need to put this in a loop.
Allright not sure if this is the place, but the answer to my own question was one expected: The server was listening in a port, and the client was sending to a different one. That was because of the way the port assigned was sent to the client: in my case, without transform it to network format (ntohs()), so when the client did htons(), the number was a completly different one.

not able to start qlocalserver

I use Qlocalsocket in my IPC solution and I am able to start the server and accept connections from QLocalSocket clients and communicate well, no prob in that.
but my problem happens when I kill the process of the server , I can't make QLocalServer listen on the same place again, I must change the service name to be able to start it again, which could not be possible at runtime environment.
so how to make the previous process to release that name?
here is how I start the server:
m_server = new QLocalServer(this);
if (!m_server->listen("serviceUniqueName")) {
qDebug() << "Not able to start the Server";
return;
}
As Amartel pointed out, if the server dies, you need to delete the socket file.
The best way to do is to call bool QLocalServer::removeServer ( const QString & name ):
m_server = new QLocalServer(this);
QString serverName("serviceUniqueName");
QLocalServer::removeServer(serverName);
if (!m_server->listen(serverName)) {
qDebug() << "Not able to start the Server";
return;
}
This way your call to listen will never fail.
Qt help:
On Unix if the server crashes without closing listen will fail with
AddressInUseError. To create a new server the file should be removed.
On Windows two local servers can listen to the same pipe at the same
time, but any connections will go to one of the server.
So, if you are using *nix, you should remove file "/tmp/socket_name".

How do I check client connection is still alive

I am working on a network programming using epoll. I have a connection list and put every client in the list. I can detect user disconnection by reading 0 if the user disconnected normally. However, if the user somehow got disconnected unexpectedly then there is no way it knows about this until it tries send data to the user.
I don't think epoll provides a nice way to handle this..so I think I should handle this on my own. I will be very appreciated if you guys can provide me anything like examples or references related to this problem.
epoll_wait will return a EPOLLHUP or EPOLLERR for the socket if the other side disconnects. EPOLLHUP and EPOLLERR are set automatically but you can also set the newer EPOLLRDHUP which explicitly reports peer shutdown.
Also if you use send with the flag MSG_NOSIGNAL it will set EPIPE on closed connections.
int resp = send ( sock, buf, buflen, MSG_NOSIGNAL );
if ( resp == -1 && errno == EPIPE ) { /* other side gone away */ }
Much nicer than getting a signal.
How about TCP Keepalives: http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html. See "Checking for dead peers". A later section on the same site has example code: http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/programming.html.

Resources