The one function used by both, clients and servers, is socket(2). It is
declared this way:
int socket(int domain, int type, int protocol);
The return value is of the same type as that of open, an
integer. FreeBSD allocates its value from the same pool as that of file handles. That is
what allows sockets to be treated the same way as files.
The domain argument tells the system what protocol family you want it to use. Many
of them exist, some are vendor specific, others are very common. They are declared in sys/socket.h.
Use PF_INET for UDP,
TCP and other Internet protocols (IPv4).
Five values are defined for the type argument, again, in
sys/socket.h. All of them start with ``SOCK_''. The most common one is SOCK_STREAM, which tells the system you are asking for a reliable stream delivery service (which
is TCP when used with PF_INET).
If you asked for SOCK_DGRAM, you would be requesting a
connectionless datagram delivery
service (in our case, UDP).
If you wanted to be in charge of the low-level protocols (such as IP), or even network interfaces (e.g., the Ethernet), you would
need to specify SOCK_RAW.
Finally, the protocol argument depends on the previous two
arguments, and is not always meaningful. In that case, use 0 for its value.
The Unconnected Socket: Nowhere, in the socket
function have we specified to what other system we should be connected. Our newly created
socket remains unconnected.
This is on purpose: To use a telephone analogy, we have just attached a modem to the
phone line. We have neither told the modem to make a call, nor to answer if the phone
rings.
Various functions of the sockets family expect the address of (or pointer to, to use C
terminology) a small area of the memory. The various C declarations in the sys/socket.h refer to it as struct
sockaddr. This structure is declared in the same file:
/*
* Structure used by kernel to store most
* addresses.
*/
struct sockaddr {
u_char sa_len; /* total length */
sa_family_t sa_family; /* address family */
char sa_data[14]; /* actually longer; address value */
};
#define SOCK_MAXADDRLEN 255 /* longest possible addresses */
Please note the vagueness with
which the sa_data field is declared, just as an array of 14 bytes, with the comment hinting there can be more than 14 of them.
This vagueness is quite deliberate. Sockets is a very powerful interface. While most
people perhaps think of it as nothing more than the Internet interface--and most
applications probably use it for that nowadays--sockets can be used for just about any kind of interprocess communications,
of which the Internet (or, more precisely, IP) is only
one.
The sys/socket.h refers to the various types of protocols
sockets will handle as address
families, and lists them right before the definition of sockaddr:
/*
* Address families.
*/
#define AF_UNSPEC 0 /* unspecified */
#define AF_LOCAL 1 /* local to host (pipes, portals) */
#define AF_UNIX AF_LOCAL /* backward compatibility */
#define AF_INET 2 /* internetwork: UDP, TCP, etc. */
#define AF_IMPLINK 3 /* arpanet imp addresses */
#define AF_PUP 4 /* pup protocols: e.g. BSP */
#define AF_CHAOS 5 /* mit CHAOS protocols */
#define AF_NS 6 /* XEROX NS protocols */
#define AF_ISO 7 /* ISO protocols */
#define AF_OSI AF_ISO
#define AF_ECMA 8 /* European computer manufacturers */
#define AF_DATAKIT 9 /* datakit protocols */
#define AF_CCITT 10 /* CCITT protocols, X.25 etc */
#define AF_SNA 11 /* IBM SNA */
#define AF_DECnet 12 /* DECnet */
#define AF_DLI 13 /* DEC Direct data link interface */
#define AF_LAT 14 /* LAT */
#define AF_HYLINK 15 /* NSC Hyperchannel */
#define AF_APPLETALK 16 /* Apple Talk */
#define AF_ROUTE 17 /* Internal Routing Protocol */
#define AF_LINK 18 /* Link layer interface */
#define pseudo_AF_XTP 19 /* eXpress Transfer Protocol (no AF) */
#define AF_COIP 20 /* connection-oriented IP, aka ST II */
#define AF_CNT 21 /* Computer Network Technology */
#define pseudo_AF_RTIP 22 /* Help Identify RTIP packets */
#define AF_IPX 23 /* Novell Internet Protocol */
#define AF_SIP 24 /* Simple Internet Protocol */
#define pseudo_AF_PIP 25 /* Help Identify PIP packets */
#define AF_ISDN 26 /* Integrated Services Digital Network*/
#define AF_E164 AF_ISDN /* CCITT E.164 recommendation */
#define pseudo_AF_KEY 27 /* Internal key-management function */
#define AF_INET6 28 /* IPv6 */
#define AF_NATM 29 /* native ATM access */
#define AF_ATM 30 /* ATM */
#define pseudo_AF_HDRCMPLT 31 /* Used by BPF to not rewrite headers
* in interface output routine
*/
#define AF_NETGRAPH 32 /* Netgraph sockets */
#define AF_MAX 33
The one used for IP is AF_INET. It is a symbol for the constant 2.
It is the address family listed
in the sa_family field of sockaddr
that decides how exactly the vaguely named bytes of sa_data
will be used.
Specifically, whenever the address
family is AF_INET, we can use struct sockaddr_in found in netinet/in.h,
wherever sockaddr is expected:
/*
* Socket address, internet style.
*/
struct sockaddr_in {
u_char sin_len;
u_char sin_family;
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
We can visualize its organization this way:

The three important fields are sin_family, which is byte 1
of the structure, sin_port, a 16-bit value found in bytes 2
and 3, and sin_addr, a 32-bit integer representation of the
IP address, stored in bytes 4-7.
Now, let us try to fill it out. Let us assume we are trying to write a client for the
daytime protocol, which simply
states that its server will write a text string representing the current date and time to
port 13. We want to use TCP/IP, so we need to specify
AF_INET in the address family field. AF_INET is defined as 2. Let us use
the IP address of 192.43.244.18, which is the time server of US federal government (time.nist.gov).

By the way the sin_addr field is declared as being of the
struct in_addr type, which is defined in netinet/in.h:
/*
* Internet address (a structure for historical reasons)
*/
struct in_addr {
in_addr_t s_addr;
};
In addition, in_addr_t is a 32-bit integer.
The 192.43.244.18 is just a convenient notation of expressing
a 32-bit integer by listing all of its 8-bit bytes, starting with the most significant one.
So far, we have viewed sockaddr as an abstraction. Our
computer does not store short integers as a single 16-bit
entity, but as a sequence of 2 bytes. Similarly, it stores 32-bit integers as a sequence
of 4 bytes.
Suppose we coded something like this:
sa.sin_family = AF_INET;
sa.sin_port = 13;
sa.sin_addr.s_addr = (((((192 << 8) | 43) << 8) | 244) << 8) | 18;
What would the result look like?
Well, that depends, of course. On a Pentium®, or
other x86, based computer, it would look like this:

On a different system, it might look like this:

And on a PDP it might look different yet. But the above two are the most common ways
in use today.
Ordinarily, wanting to write portable code, programmers pretend that these differences
do not exist. And they get away with it (except when they code in assembly language).
Alas, you cannot get away with it that easily when coding for sockets.
Why?
Because when communicating with another computer, you usually do not know whether it
stores data most significant byte
(MSB) or least significant byte (LSB) first.
You might be wondering, ``So, will sockets
not handle it for me?''
It will not.
While that answer may surprise you at first, remember that the general sockets
interface only understands the sa_len and sa_family fields of the sockaddr
structure. You do not have to worry about the byte order there (of course, on FreeBSD
sa_family is only 1 byte anyway, but many other UNIX® systems do not have sa_len
and use 2 bytes for sa_family, and expect the data in whatever
order is native to the computer).
But the rest of the data is just sa_data[14] as far as
sockets goes. Depending on the address
family, sockets just forwards that data to its destination.
Indeed, when we enter a port number, it is because we want the other computer to know
what service we are asking for. And, when we are the server, we read the port number so
we know what service the other computer is expecting from us. Either way, sockets only
has to forward the port number as data. It does not interpret it in any way.
Similarly, we enter the IP address to tell everyone
on the way where to send our data to. Sockets, again, only forwards it as data.
That is why, we (the programmers, not the sockets) have to distinguish between the byte order used by
our computer and a conventional byte order to send the data in to the other computer.
We will call the byte order our computer uses the host byte order, or just the host order.
There is a convention of sending the multi-byte data over IP MSB first. This, we will refer to as the network byte order, or simply the network order.
Now, if we compiled the above code for an Intel based computer, our host byte order would produce:

But the network byte order
requires that we store the data MSB first:

Unfortunately, our host order is
the exact opposite of the network
order.
We have several ways of dealing with it. One would be to reverse the values in our code:
sa.sin_family = AF_INET;
sa.sin_port = 13 << 8;
sa.sin_addr.s_addr = (((((18 << 8) | 244) << 8) | 43) << 8) | 192;
This will trick our compiler
into storing the data in the network byte
order. In some cases, this is exactly the way to do it (e.g., when programming
in assembly language). In most cases, however, it can cause a problem.
Suppose, you wrote a sockets-based program in C. You know it is going to run on a
Pentium, so you enter all your constants in reverse and
force them to the network byte
order. It works well.
Then, some day, your trusted old Pentium becomes a
rusty old Pentium. You replace it with a system whose
host order is the same as the network order. You need to recompile all
your software. All of your software continues to perform well, except the one program you
wrote.
You have since forgotten that you had forced all of your constants to the opposite of
the host order. You spend some
quality time tearing out your hair, calling the names of all gods you ever heard of (and
some you made up), hitting your monitor with a nerf bat, and performing all the other
traditional ceremonies of trying to figure out why something that has worked so well is
suddenly not working at all.
Eventually, you figure it out, say a couple of swear words, and start rewriting your
code.
Luckily, you are not the first one to face the problem. Someone else has created the htons(3) and htonl(3) C functions
to convert a short and long
respectively from the host byte
order to the network byte
order, and the ntohs(3) and ntohl(3) C functions
to go the other way.
On MSB-first systems these functions do nothing. On
LSB-first systems they convert values to the proper
order.
So, regardless of what system your software is compiled on, your data will end up in
the correct order if you use these functions.