4 ms·
> Lots of the complexity of TCP at a protocol level comes from treating it as a single duplex connection instead of a pair of simplex connections. I've created
by rstuart4133 3y ago
> Lots of the complexity of TCP at a protocol level comes from treating it as a single duplex connection instead of a pair of simplex connections.
I've created a few communication protocols in my time (all people of a certain age have, because we pre-date TCP/IP), and I am reasonable familiar with TCP itself. I don't see the extra complexity you speak of. At most, it is de-multiplexing the ACK fields in the header from the rest. If you want to whinge about unnecessary complexity in the TCP protocol, I'd suggest starting with it being byte orientated rather than packet orientated.
Secondly Dan is out of touch. He's right in saying it's a complex solution for a shell pipeline, but the TCP is designed to operate in a less reliable world. In TCP's world you can no longer assume a message you sent was acted upon by the other end. The network could have died, or the system crashed before the data made it to disk. Thus the shell command:
echo Run for your life or you will die | mail friend@doomed.com
is perfectly reasonable. You know the message will make it or you will be told something went wrong. But if the "mail" command is running on a different machine, unsupervised, then you have no idea the message made it unless the mail programs sends a message back saying "email safely and durably received". That requires a back channel. You almost always require a back channel for that reason and what's worse, they are a pita to set up using unidirectional pipes. That makes a unidirectional pipe is a terrible API for sending messages to a remote location.
It looks like TCP's successor will be QUIC. In QUIC there isn't just two streams, you can create lots of sub-streams, using datagrams if you want. Now that is a lot of extra complexity. But from the applications point of view it's a very nice feature. It's a bit like the second channel TCP gives you, as it's surprising how often you need a more than one channel between two programs. In fact the very first use TCP was put to was FTP and guess what - FTP creates two TCP connections. And it's example of how painful it can be to set that up as NAT broke the original FTP for a while. We now finally have an off the shelf solution in QUIC. It only took 30+ years to arrive.
It looks to me like the world has voted. The outcome is a firm Nay to Dan's suggestion, and it's now moving in the opposite direction.
- dfawcus 3y ago"And it's example of how painful it can be to set that up as NAT broke the original FTP for a while." NAT broke FTP for about the 5 seconds it took for one to realise they needed to type in the PASV command - which existed right from the start. It was in RFC 542 (1973) - pre TCP, and RFC 765 (1980) - first post TCP. NAT dates from around 1994.
- tonyg 3y agoPASV works around some but not all NAT breakage. There are things FTP can do outside a NAT that it can't do with a NAT around. (Workarounds can be concocted, but NAT really did take away some of the natural abilities of FTP.)
- tonyg 3y agoThe complexity I have in mind is roughly that the TCP state machine isn't quite the cartesian product of two opposed unidirectional state machines, but it could be. (No proof of this, only a TCP implementation based on the idea. I really must sort the question out rigorously one of these days.) Re the reliability: the same is true of pipes. You can't assume `mail` will take the message, even with pipes, because, just as with TCP, there's no feedback channel. The disk could have filled up after `mail` took the final bytes from its input, for example. Your point about application-level acknowledgements is 100% spot on, then, but pipes need application-level acks too, in much the same circumstances as TCP would, for just the same reasons. Even pipes make a distributed system. Not all protocols need application-level acks, though. In the `echo | mail` example, you do get feedback that the process exited abnormally, but this is feedback to the supervisor (here, the shell), not to the preceding process in the pipeline. The same could (and should) be arranged for a TCP-based link between `echo` and `mail`. The failure-signalling takes on some of the responsibilities than an app-level ack would have discharged. Pipes vs sockets makes no difference. Your point about the difficulty of constructing the necessary back-channels for app-level acks is also spot on. If one were to reformulate a transport layer in terms of simplex channels, one would want to retain an easy way to configure a pair of them as a single duplex channel. This is as true of pipes as of sockets. A nice design would allow capability-passing as well as regular message sending: then, you'd open an outbound stream to a server, and as your first message, you'd send a capability for the write-end of a matching inbound stream. Modular session establishment. Permits a bunch of other interaction patterns, too, such as session handoff, redirection, continuation-passing, load-balancing etc. Richer topological possibilities even than SCTP and QUIC. If capability-passing was in TCP, it'd have been trivially handled by the NAT, too, so FTP wouldn't have been broken. Ah well, never mind. All that said, Dan isn't taking aim at TCP-the-protocol here. (He does, elsewhere.) Instead, the focus is the sockets API. The API could easily have involved two unidirectional fds instead of just one, without changing the protocol, or how easy/difficult it is to establish a connection. It'd just expose a read cap and a write cap instead of a single mixed capability. It'd be a small change that'd eliminate a bunch of special-casing. I think he has a good point; it's a shame we can't get there from here...
- rstuart4133 3y ago