This article collects my opinions concerning the programming interfaces available for making network requests which are commonly available or enforced by the operating system. I'll update this article as I've more to write of and feel the want.
The most common programming interface for making network requests is, quite unfortunately, the POSIX Sockets mechanism. To use the interface from a real language requires scanning for named constants; converting the very poorly defined type definitions, which contain waste yet were still insufficient for IPv6 support; and undergoing poor rituals to ask the system to give access to the resource, with the potential for failure at every step, several of which are unnecessary. Merely initializing such a socket is an operation which can fail; binding it can fail, although failure to bind to a port has an inherent failure case, along with binding and socket initialization being entirely separate; once this is finished, the socket may be used, but behaves largely as a file.
The POSIX Sockets mechanism uses similar terminology to the IETF RFCs and yet I can't believe such a disgusting interface was intended. The lack of abstraction, forethought, and poor language used for this monster is responsible for the visceral disgust it leaves me with, I think.
I firmly believe proper system design takes pain unto itself to eliminate edge cases. A proper such system would provide the option of treating wildly different I/O sources as the same, but permit the reducing of failure cases for any single one by permitting avoiding this. It may seem reasonable to give a terminal, file system, and TCP similar interfaces, yet this group poses necessarily different failure cases. The source of input for a terminal is usually a human and so a read can't fail, with a potentially indefinite wait; a file system can make a request, yet fail due to recognized hardware failure or semantic issues with the underlying model; a TCP connection can fail for many reasons and may result in failure from which there's no reasonable recovery mode. Collapsing these under a lone interfaces collapses their failure modes into a single model, as well, and it should be realized the addition of invariants through a lack of genericity is valuable.
Another very important aspect of my idealized network programming interfaces is creating hard splits between client and server usage. A TCP client can operate with basic functionality, similarly to an interface with a file system, and all advanced or obscure choices being optional with good defaults. A TCP server, however, is entirely different; I believe such a TCP server interface should provide a mechanism for creating new connections as asked of it perhaps with such connections behaving largely as a TCP client afterwards; the most important aspect is there is no fiction that the same interface for wildly different purposes is sufficient or excusable. The former is active, the latter passive, and the latter being a generator mechanism, where there's no such concept for the former.
A protocol such as UDP blurs the distinction between client and server sufficiently well that a lone interface is sufficient. A generator mechanism similar to the TCP server seems best, with this idea being that the object is given messages and provides them. There are, of course, many options which should be accounted for, no differently than as for TCP.
Neither of these TCP or UDP interfaces should be arduous to use; in a high-level language, each must be a single invocation of some such interface, probably on a single program line. That such a minor thing is made so difficult and complicated for modern systems is an indictment of their poor design.
The underlying IP interface should also be usable, in a similar way, with its settings transparently taking effect and the overlying interfaces using them without question. A bothersome quality is the difficulty a modern system poses in using fake port and IP addresses for IP, but the case made could betray this as a rather minor issue and something which should be restricted.
For further thoughts, see the documentation of my EASY-PEASY-TCP Common Lisp library experiment.