Different computer processors represent numbers in big-endian and little-endian form, depending on how they are designed. For example, on Intel x86 processors, multibyte numbers are represented in little-endian form: the bytes are ordered from least significant to most significant. When an IP address and port number are specified as multibyte quantities in a computer, they are represented in host-byte order. However, when IP addresses and port numbers are specified over a network, Internet networking standards specify that multibyte values must be represented in big-endian form (most significant byte to least significant), normally referred to as network-byte order.
A series of functions can be used to convert a multibyte number from host-byte order to network-byte order and vice versa. The following four API functions convert a number from host-byte to network-byte order:
Host to Network-byte converter API Functions |
|
1 |
u_long htonl(u_long hostlong); |
2 |
int WSAHtonl(SOCKET s, u_long hostlong, u_long FAR * lpnetlong); |
3 |
u_short htons(u_short hostshort); |
4 |
int WSAHtons(SOCKET s, u_short hostshort, u_short FAR * lpnetshort); |
The hostlong parameter of htonl() and WSAHtonl() is a four-byte number in host-byte order. The htonl() function returns the number in network-byte order, whereas the WSAHtonl() function returns the number in network-byte order through the lpnetlong parameter. The hostshort parameter of htons() and WSAHtons() is a two-byte number in host-byte order. The htons() function returns the number as a two-byte value in network-byte order, whereas the WSAHtons() function returns the number through the lpnetshort parameter.
The next four functions are the opposite of the preceding four functions; they convert network-byte order to host-byte order.
Network to Host-byte Converter API Functions |
|
1 |
u_long ntohl(u_long netlong); |
2 |
int WSANtohl(SOCKET s, u_long netlong, u_long FAR * lphostlong); |
3 |
u_short ntohs(u_short netshort); |
4 |
int WSANtohs(SOCKET s, u_short netshort, u_short FAR * lphostshort); |
We will now demonstrate how to address IPv4 by creating a SOCKADDR_IN structure using the inet_addr() and htons() functions described previously.
SOCKADDR_IN InternetAddr;
INT nPortId = 5150;
InternetAddr.sin_family = AF_INET;
// Convert the proposed dotted Internet address 136.149.3.29
// to a four-byte integer, and assign it to sin_addr
InternetAddr.sin_addr.s_addr = inet_addr(136.149.3.29);
// The nPortId variable is stored in host-byte order. Convert
// nPortId to network-byte order, and assign it to sin_port.
InternetAddr.sin_port = htons(nPortId);
As you can probably tell, IP addresses aren't easy to remember. Most people would much rather refer to a machine (or host) by using an easy-to-remember, user-friendly host name instead of an IP address. Hopefully, in other chapters we will describe useful address and name resolution functions that can help you resolve a host name, such as www.gedik.com, to an IP address and a service name, such as FTP, to a port number using functions such as getaddrinfo(), getnameinfo(), gethostbyaddr(), gethostbyname(), gethostname(), getprotobyname(), getprotobynumber(), getservbyname(), and getservbyport(). There are also some asynchronous (non-blocking) versions of some of these functions:
Keep in mind that some of the functions may already deprecated. Now that you have the basics of addressing a protocol such as IPv4, you can prepare to set up communication by creating a socket.
If you're familiar with Winsock, you know that the API is based on the concept of a socket. A socket is a handle to a transport provider. In Windows, a socket is not the same thing as a file descriptor and therefore is a separate type: SOCKET in WINSOCK2.H. There are two functions that can be used to create a socket: socket and WSASocket. In the simplest form, we will briefly describe socket as:
SOCKET socket (int af, int type, int protocol);
The first parameter, af, is the protocol's address family. Since we describe Winsock in this chapter using only the IPv4 protocol, you should set this field to AF_INET.
The second parameter, type, is the protocol's socket type. When you are creating a socket to use TCP/IP, set this field to SOCK_STREAM, for UDP/IP use SOCK_DGRAM.
The third parameter is protocol and is used to qualify a specific transport if there are multiple entries for the given address family and socket type. For TCP you should set this field to IPPROTO_TCP; for UDP use IPPROTO_UDP. Chapter 2 describes socket creation in greater detail for all protocols, including the WSASocket API. Winsock features four useful functions to control various socket options and socket behaviors: setsockopt(), getsockopt(), ioctlsocket(), and WSAIoctl(). For simple Winsock programming, you will not need to use them specifically. Once you have successfully created a socket, you are ready to set up communication on the socket to prepare it for sending and receiving data. In Winsock there are two basic communication techniques: connection-oriented and connectionless communication.
In this section, we'll cover the Winsock functions necessary for both receiving connections and establishing connections. We'll first discuss how to develop a server by listening for client connections and explore the process for accepting or rejecting a connection. Then we'll describe how to develop a client by initiating a connection to a server. Finally, we'll discuss how data is transferred in a connection-oriented session. In IP, connection-oriented communication is accomplished through the TCP/IP protocol. TCP provides reliable error-free data transmission between two computers. When applications communicate using TCP, a virtual connection is established between the source computer and the destination computer. Once a connection is established, data can be exchanged between the computers as a two-way stream of bytes.