The source code for the echo client is as follows5:
#include<stdio.h> #include<netinet/in.h> #include<sys/types.h> #include<string.h>
/* Host and port number of the echo server */ char* echo_host = "192.168.1.20"; int echo_port = 7; int sockfd;
struct sockaddr_in *server=
(struct sockaddr_in*)malloc(sizeof(struct sockaddr_in));
/* Set address of server to be connected */ server->sin_family = AF_INET;
server->sin_port = htons(echo_port); // Note network byte order!
server->sin_addr.s_addr = inet_addr(echo_host);
/* Create a socket (Internet address family, stream socket and default protocol) */ sockfd = socket(AF_INET, SOCK_STREAM, 0);
printf("Connecting to %s \n", echo_host); printf("Numeric: %u\n", server->sin_addr);
connect(sockfd, (struct sockaddr*)server, sizeof(*server));
/* Send message */ char* msg = "Hello World"; printf("\nSend: '%s'\n", msg); write(sockfd, msg, strlen(msg));
char* buf = (char*)malloc(1000); // Receive buffer for max. 1000 chars int bytes = read(sockfd, (void*)buf, 1000);
5 To simplify matters, all error checks that would be performed in a genuine, robust implementation are omitted.
printf("\nBytes received: %u\n", bytes); printf("Text: '%s'\nM, buf);
/* End communication (i.e. close socket) */ close(sockfd);
The Internet superdaemon (inetd, xinetd, or similar) normally uses a built-in echo server. Consequently, the source code can be tested immediately after compilation.
[email protected]> ,/echo_client Connect to 192.168.1.20 Numeric: 335653056
Send: 'Hello World'
Bytes received: 11 Text: 'Hello World'
The following steps are performed by the client:
1. An instance of the sockaddr_in structure is generated to define the address of the server to be contacted. AF_INET indicates that it is an Internet address and the target server is precisely defined by its IP address (192.168.1.20) and port number (7).
Also, the data from the host are converted to the network byte order. htons is used for the port number, and the inet_addr auxiliary function performs the conversion implicitly by translating the text string with a dotted decimal address into a number.
2. A socket is created in the kernel by means of the socket function, which (as shown below) is based on the socketcall system call of the kernel. The result returned is an integer number that is interpreted as a file descriptor — and can therefore be processed by all functions available for regular files, as described in Chapter 8. In addition to these operations, there are other network-specific ways of handling the file descriptor; these permit exact setting of various transmission parameters not discussed here.
3. A connection is set up by invoking the connect function in conjunction with the file descriptor and the server variable that stores the server connection data (this function is also based on the socketcall system call).
4. Actual communication is initiated by sending a text string (''Hello World'' — how could it be anything else?) to the server by means of write. Writing data to a socket file descriptor is the equivalent of sending data. This step is totally independent of the server location and the protocol used to set up the connection. The network implementation ensures that the character string reaches its destination — no matter how this is done.
5. The server response is read by read, but a buffer must first be allocated to hold the data received. As a precaution, 1,000 bytes are reserved in memory, although we only expect the original string to be returned. read blocks until the server supplies a response, and it then returns the number of bytes received as an integer number.
Because strings in C are always null-terminated, 11 bytes are received, although the message itself appears to be only 10 bytes long.
Continue reading here: Echo Server
Was this article helpful?