So for, we have assumed that both the server and client run on the same computer using localhost or IP= 127.0.0.1, and the server uses a fixed port number. If the reader intends to run the server and client on different hosts with a server port number assigned by the OS kernel, it is necessary to know server’s host name or IP address and its port number. If a computer runs TCP/IP, its hostname is usually recorded in the /etc/hosts file. The library function
gethostname(char *name, sizeof(name))
returns the machine’s hostname string in a name array, but it may not be the full official name in dot notation, nor its IP address. The library function
struct hostent *gethostbyname(void *addr, socklen_t len, int typo)
can be used to get the full name of the machine, as well as its IP address. It returns a pointer to a hostent structure in <netdb.h>, which is
Note that h_addr is defined as a char *, but it points at a 4-byte IP address in network byte order. The contents of h_addr can be accessed as
u32 NIP = *(u32 *)h_addr is the host IP address in network byte order.
u32 HIP = ntohl(NIP) is NIP in host byte order.
inet_ntoa(NIP) converts NIP to a string in DOT notation.
The following code segments show how to use gethostbyname() and getsockname() to get the server IP address and port number if it is dynamically assigned. The server must publish its hostname or IP address and port number for clients to connect.
/********* TCP server code *********/
char myname[64];
struct sockaddr_in server_addr, sock_addr;
// 1. gethostname(), gethostbyname()
gethostname(myname,64);
struct hostent *hp = gethostbyname(myname);
if (hp == 0){
printf(“unknown host %s\n”, myname); exit(1);
}
// 2. initialize the server_addr structure
server_addr.sin_family = AF_INET; // for TCP/IP
server_addr.sin_addr.s_addr = *(long *)hp->h_addr;
server_addr.sin_port =0; // let kernel assign port number
// 3. create a TCP socket
int mysock = socket(AF_INET, SOCK_STREAM, 0);
// 4. bind socket with server_addr
bind(mysock,(struct sockaddr *)&server_addr, sizeof(server_addr));
// 5. get socket addr to show port number assigned by kernel
getsockname(mysock, (struct sockaddr *)&name_addr, &length);
// 6. show server host name and port number
printf(“hostname=%s IP=%s port=%d\n”, hp->h_name,
inet_ntoa(*(long *)hp->h_addr), ntohs(name_addr.sin_port));
/********* TCP client code *********/
// run as client server_name server_port
struct sockaddr_in server_addr, sock_addr;
// 1. get server IP by name
struct hostent *hp = gethostbyname(argv[1]);
SERVER_IP = *(long *)hp->h_addr;
SERVER_PORT = atoi(argv[2]);
// 2. create TCP socket
int sock = socket(AF_INET, SOCK_STREAM, 0);
// 3. fill server_addr with server IP and PORT#
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = SERVER_IP;
server_addr.sin_port = htons(SERVER_PORT);
// 4. connect to server
connect(sock,(struct sockaddr *)&server_addr, sizeof(server_addr));
Incorporating hostname and IP address into the TCP server-client program is left as exercises in the problem section.
Source: Wang K.C. (2018), Systems Programming in Unix/Linux, Springer; 1st ed. 2018 edition.