Socket address structures are an integral part of every network program. We allocate them, fill them in, and pass pointers to them to various socket functions. Sometimes we pass a pointer to one of these structures to a socket function and it fills in the contents. We always pass these structures by reference (that is, we pass a pointer to the structure, not the structure itself), and we always pass the size of the structure as another argument. When a socket function fills in a structure, the length is also passed by reference, so that its value can be updated by the function. We call these value-result arguments. Socket address structures are self-defining because they always begin with a field (the "family") that identifies the address family contained in the structure. Newer implementations that support variable-length socket address structures also contain a length field at the beginning, which contains the length of the entire structure. The two functions that convert IP addresses between presentation format (what we write, such as ASCII characters ) and numeric format (what goes into a socket address structure) are inet_pton and inet_ntop . Although we will use these two functions in the coming chapters, they are protocol-dependent. A better technique is to manipulate socket address structures as opaque objects, knowing just the pointer to the structure and its size. We used this method to develop a set of sock_ functions that helped to make our programs protocol-independent. We will complete the development of our protocol-independent tools in Chapter 11 with the getaddrinfo and getnameinfo functions. TCP sockets provide a byte stream to an application: There are no record markers. The return value from a read can be less than what we asked for, but this does not indicate an error. To help read and write a byte stream, we developed three functions, readn , writen , and readline , which we will use throughout the text. However, network programs should be written to act on buffers rather than lines. |