i've got this problem, in a test program, where i'm developing a client for MQTT, i'm subscribed on a topic, after that, i wait for "publish" message from the server to my client.
After a good recv (of a publish message) or after a recv timeout i send a mqtt PINGREQ to the server.
After a A PINGREQ i'm going to wait a PINGRESP, then i call a recv as in the case I were waiting for a PUBLISH message.
If the flow is this:
Client -> PINGREQ
Server -> PUBLISH
Server -> PINGRESP
Than the server publish message were lost. How to solve this? I'm using MQTT at QOS 0, it make sense solve this problem on this level of QOS or instead is smart to check this case at QOS1?
I think you've got things a bit confused. PINGREQ/PINGRESP are used when there isn't any other network traffic passing between the client and server, in order to let both the client and server know if the connection drops.
Your client should keep track of the when the last outgoing or incoming communication with the server was, and send a PINGREQ if it is going to exceed the keepalive timer it set with its CONNECT command. The server will disconnect the client at 1.5*keepalive if no communication is received. The client should assume the server has been disconnected if it does not receive a PINGRESP in response to its PINGREQ within keepalive of sending the PINGREQ.
The QoS level isn't that important, you have to ensure the keepalive timeout is maintained regardless.
It also occurs to me that it sounds like you're using blocking network calls - it might be best to move to non-blocking if you can to get more flexibility.
Related
I have a server written in C that closes the connection if the connection is sitting idle for a specific time. I have an issue (that rarely happens). Read is failing on the client side and it says Connection broken. I suspect the server is closing the connection and the client is sending some data at the same time.
Consider the following scenario (A is server, B is the client)
B initiates the connection and the connection between A and B is established.
B is sitting idle and the idle timeout is reached.
A initiates the close
Before B receives the FIN from A, it starts sending request to A
After B sends the request, it will read the response
Since A has already closed the connection, B is not able to read.
My questions are
Is this a possible situation ?
How to handle idle timeout for clients?
How to close the connection between A and B properly (avoid B sending request during the process). In short, how to close the connection atomically?
By my only little more than rudimentary network experience... and assuming that you are talking about a connection-oriented connection like TCP/IP in contrary to UDP/IP that is connection-less.
Yes, of course. You cannot avoid it.
There are multiple ways to do it, but all of them include: Send something from the client before the server's timeout elapses. If the client has no data to send, let it send something like a "life sign". This could be an empty data message, it all depends on your application protocol. Or make the timeout as long as necessary, including some margin. Some protocol timeout only after 3 times of allowed idle time.
You cannot close the connection atomically, because client and server are separated. Each packet on the network needs some time to be transmitted, and both can start sending at the very same moment, the server its closing message, and the client a new data message. There is nothing that you can do about this.
You need to make the client handle this situation properly. For example, it can accept such a broken connection and interpret it as closed. You should have already some reaction, if the server closes the connection while the client is idle.
How to close the connection between A and B properly (avoid B sending request during the process).
Server detects timeout
Server sends timeout detection message to the Client
Server waits for a reply (if timeout, assume Client dead)
if Client receives a timeout detection from the Server, it replies with ACK (or something like that)
if Server receives an ACK from the Client, then 'gracefully' closes the connection
from now on, neither the Server nor the Client should send/receive any messages (after sending the ACK, do not immediately close the connection from the client side, do linger for the agreed timeout - see setsockopt: SO_LINGER)
On top of that, like the other answers suggested, the Client should send a heartbeat if idle (to avoid timeout detections).
I wrote my own server with epoll. When I sent TCP keep alive packages from client to server, epoll event will not get triggered. Question: I want my server to keep the connection open when server gets tcp keep alive packages.
I also tried to look at tcp info but there are no update for its attributes when server got keep alive packages.
I understand tcp keep alive packages is no data but header. I saw in my tcpdump, kernel sent back tcp keep alive ACK after received keep alive package. My goal is to keep connection open when keep alive arrives (kind like reset timer in my server, my server can close connection in no tcp real data)
I set up my client to make connection and send data (e.g "hello world") then send keep alive packages to server.
My server is epoll triggered. I already also tried to set my server to be non-blocking.
// epoll setting I tested
EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET
(most questions I found on internet are related to client side, my question is more towards server or receiver side of tcp keep alive, how to keep it open)
No, this is not possible as far as I know.
You will have to implement a heartbeat in the application protocol, and then you can stop using TCP keepalive.
I'm trying to write a TCP client with write function following this: guide.
I shut down my network and try to send a PING package with 2 bytes of data.
Since it's a TCP client, I expect some kind of error returned because there is no network at all and the server won't be able to receive the message, hence no ACK packet will be returned. However, write function returns 2 bytes were written, seem like it doesn't verify ACK packet from server side at all.
How could I check for ACK to make sure whether my message is sent successfully and server receive it?
If you run both client and server on the same machine they'll communicate through the loopback interface, so unplugging or deactivating the outbound network interface will not change anything. Your server and client communicate happily with each other. If there truly isn't any connection between server and client the connect() should've failed with errno set to ENETUNREACH or ECONNREFUSED if the server refuses the connection. So what you probably want is to run the client on your machine and the server either another computer or in a VM with a bridged network. Note that write() successfully returning only means that the bytes are buffered to be send. It may even return fewer bytes than your message contains, indicating the buffer is currently full and you need to try sending the remaining bytes later.
The best way to analyze protocol implementations is using a tool like wireshark to see what packages are actually sent over the wire (or through the loopback interface).
Isn't if the server did not receive any messages from the client within the (1.5) * KeepAlivetime and the client did not send any PINGREQ within the aforementioned period, the server should DISCONNECT?
If yes, why I am receiving LWT message which is should not be received as DISCONNECT occures?
Last will and Testement will be sent if the client does not explicitly disconnect it's self.
If the broker disconnects the client due to a ping time out then the LWT will be sent, this is the specific reason why the LWT feature exists.
Or do you mean your now disconnected client is receiving it's own LWT?
Can a process open/maintain 2 TCP connections in parallel? [for sending and receiving].
I tried the following scenario :
1) Client connects to server on one port, say 13101.
2) Once it sends, it will wait on another port 13102 to get the ACK.
3) Here Server can handle multiple connections [using select() on same port number].
Now, I am facing 2 problems:
1) Server on receiving data from Client1, it is processing data and for sending the ACK back [to client1], I am preparing a new TCP connection [with port 13102] and trying to send data. It fails with "Connection Refused".
2) In order to verify the above problem, I wrote another client2 program that just sends data to port 13102 [to client1, when it is in listening mode]. Still client2 is getting "Connection refused" error.
Yes, you can open lots of sockets! However, you shouldn't need separate sockets for sending and receiving, a TCP socket is bi-directional once it's opened.
As for your error, if you're using two machines, there could be a firewall preventing the server from connecting to your client. You might try using telnet to try to connect to the same port.
The error is probably because the client is not listening for an incoming connection. As stated above you can use a single socket for both send and receive.