[Interest] TCP ACK with QDataStream -- OR: disconnect race condition detection

Konrad Rosenbaum konrad at silmor.de
Mon Sep 10 21:43:11 CEST 2012


Hi,

let's cut it short and come back to your problem.

On Sunday 09 September 2012 20:54:09 d3fault wrote:
> Haha, funny. Reliable doesn't mean reliable. Who knew...

No it is just a different kind of reliable.

TCP reliable: TCP guarantees that you have a stream. Bytes arrive at the 
application in the order they were sent (even if packets arrive out of order 
in the OS or are dropped) - no gaps, no reordering. The data in the stream is 
(reasonably) reliable against mild (non-intentional) line noise (each TCP 
packet has a 16bit checksum). Bytes either arrive intact or not at all.

This is were the use of TCP ACK ends - it ensures that you have a stream. 
That's it. End of story. (Thiago made much more detailed arguments if you want 
to delve into the details - I recommend just accepting it - he knows what he 
is talking about.)

Application reliable: you can guarantee that a transaction (as per the 
application's definition of transaction) is executed completely or not at all.

You do this with an application level protocol. There is no way around it. 
Even if it is a very simple one. See below.

Naive newbie reliable: you can magically ensure that data is transported and 
acted on even if it has to cross broken glass bare footed while being shot at 
during a power outage. This is unrealistic and physically impossible - if you 
want to know the details - read up on entropy, quantum physics and a few other 
subjects that waste a lot of development time - or you may just take the word 
of people who tried and failed (like me).

> Are you sure it isn't just Qt failing to utilize the TCP protocol
> correctly? I don't mean to question your expertise, as you sound like
> you know what you're talking about, but this quote from wikipedia
> makes it sound like TCP does in fact do mid-stream reliability: "TCP
> primarily uses a cumulative acknowledgment scheme, where the receiver
> sends an acknowledgment signifying that the receiver has received all
> data preceding the acknowledged sequence number" [0]. That plus
> automatic re-transmission of lost packets sounds like exactly what I
> want! How do I get that number in a platform independent manner [and
> make sense of it]?

See above. Qt's utilization of TCP gives you exactly the guarantees that TCP 
itself gives you. You have a stream that is reliable on the transport level. 
(Reliable = arrives as expected or not at all)

Hence: if QTcpSocket tells you the data is written this means the data is on 
its way in the order you wrote it. That's it. No guarantee that it does not 
get eaten by a grue before it arrives. If byte N gets eaten on all repeated 
attempts, then byte N+1 is dropped as well and the connection breaks.

> I was going to code my own ack layer on top of TCP... but after a few
> designs and reading further into TCP it sounded an awful lot like
> reinventing the wheel. I came up with my own sequence number scheme
> and everything and oh boy TCP really sucks if you're right :-P...

Fortunately you don't need to *reinvent* the wheel. Real honest to god 
computer scientists have done that before. All you need to do is read up on 
the subject and then build a wheel that fits your cart. ;-)

> An actually-reliable-tcp-socket class (called something else, and
> perhaps based on QAbstractSocket instead?) sounds like it would make a
> great addition to Qt don't you think? Maybe something along the lines
> of QNetworkRequest::Acknowledged() [signal].... though not necessarily
> anything to do with QNAM (especially since the QNetworkReply makes a
> better acknowledgement in that case lol (and now I'm just confusing
> myself)).

No, use TCP socket and use the guarantees it gives you: a stream that arrives 
in order with data secured against physical noise.

It does not give you:
1) application transactions
2) security against malicious attackers(1)
3) magical abilities

Let's do this in reverse order: 3 is not achievable in this universe. Let's 
drop it. When you write your spec I expect you to write down that your 
protocol does not magically overcome disconnected networks.

Security against malicious attackers has been solved before: your interface to 
it is QSslSocket (which incidentally also relies on the guarantees of TCP). 
From my own experience: do not try to solve this yourself. Use a proven 
implementation like QSslSocket. Even if it breaks the SSL experts know better 
than the two of us how to fix it.

Finally application transactions. This is where you need to spend some 
thinking time.

Define what a message in your application is - a completely transferred file, 
an update to the screen,... ; is there just one message in one connection or 
do you plan to send many messages in the same stream?

Define a transaction: what actions does the recipient of a message take? Can 
the next action be taken even if it is still unclear whether the first one 
succeeded? What can go wrong on the transport, during reception, during 
processing? What information does the sender need about success or failure?

Your protocol can be as simple as HTTP 0.9: client sends a single line "GET 
/myfile.html", server sends the file and then closes the TCP socket. In this 
case the client sees from the way the socket is closed whether it received the 
entire file (normal close) or something went wrong on the network (error).

It could be a complex concurrent protocol like IMAP: you can put several 
requests for folder listings and mail contents into the queue and the server 
will respond marking its messages with a tag that allows you to know which 
question the answer belongs to. Failed requests do not influence the other 
requests.

It could be a complex transactional protocol with a strict order of execution, 
like the protocols used by databases (a transaction has to succeed or fail 
before you start the next one).

What you do not need to do with TCP: 
* you do not need to ensure messages arrive in order. 
* You do not need to cut messages into packets. 
* You do not need to reassemble them. 
* You do not need to checksum them against physical defects.

If you use QSslSocket:
* You do not need to implement cryptographic authentication algorithms, you 
can use certificates.
* You do not need to secure against malicious attackers altering your data - 
SSL does that.

What you do need to do is to define your application layer:
* Define your messages.
* Define your transactions.
* Actually use some form of authentication if applicable.




	Konrad
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20120910/9f00f4b0/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part.
URL: <http://lists.qt-project.org/pipermail/interest/attachments/20120910/9f00f4b0/attachment.sig>


More information about the Interest mailing list