Simple time-of-day TCP Client-Server model example using sockets in C
This program returns time of day whenever a client send server a packet. Using this example we will understand basics of TCP sockets.
In a client-server model, a server is an application program that offers a service over a network. The server's code runs first, which opens a port and accepts an incoming request. When a request arrives it forms a response and returns the result to the requester. A program becomes a client when it sends a request to a server and waits for a response.
Source code for other similar programs
- Time of day client-server program using TCP sockets
- Example of echo server using TCP sockets
- Simple chat using TCP sockets
- Echo server but built with concurrent server
- Simple chat but built with concurrent server
- Implementation of a TCP Quiz program
- [WIP] Provide Registration Number
- [WIP] Client-to-Client Communication Chat
Time-of-Day
Here, when a client is connected to a server. The server will send current time information to the client and the client will print the information in the screen.
Server Side Code
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define MAXLINE 1024
#define LISTENQ 10
typedef struct sockaddr SA;
int main(int argc, char **argv){
int listenfd, connfd;
struct sockaddr_in servaddr, cliaddr;
char buff [MAXLINE];
time_t ticks;
int port;
socklen_t len;
listenfd = socket(AF_INET, SOCK_STREAM, 0); // Creates a TCP Socket
port = atoi(argv[1]);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
printf("Server is waiting connection at port %d\t\n", port);
listen(listenfd, LISTENQ);
for ( ; ; ) {
len = sizeof(cliaddr);
connfd = accept(listenfd, (SA *) &cliaddr, &len);
printf("Connection from %s, port %d\n", inet_ntop(AF_INET,
&cliaddr.sin_addr.s_addr, buff, sizeof(buff)), ntohs(cliaddr.sin_port));
ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
write(connfd, buff, strlen(buff));
close(connfd);
}
}
1. Include header files
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
These line includes numerous system headers that are needed by most network programs
2. Defines Constants
#define MAXLINE 1024
#define LISTENQ 10
Defines various constants that we use(e.g., MAXLINE, LISTENQ)
3. Gives type "struct sockaddr" a new name to shorten the code.
typedef struct sockaddr SA;
- Starts main function and it accepts command line arguments.
int main(int argc, char **argv){
argc (argument count) and argv (argument vector) are how command line arguments are passed to main() in C and C++.
argc will be the number of strings pointed to by argv.
5. Creates a TCP Socket.
listenfd = socket(AF_INET, SOCK_STREAM, 0); // Creates a TCP Socket
The socket function creates a socket on demand. The function takes three integer arguments and returns an integer descriptor which we can use to identify the socket in all future function calls (e.g., the calls to connect and read that follow).
6.Initialize the server address by the port and IP.
port = atoi(argv[1]);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
7. Bind the socket descriptor to the server address.
bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
Once a socket has been created, a server uses the bind function to establish a local address for the socket†. Bind has the following form.
bind(descriptor, localaddr, addrlen)
8. Turn on the socket to listen for incoming connections.
listen(listenfd, LISTENQ);
Socket function listen allows servers to prepare a socket for incoming connections. In terms of the underlying protocols, listen puts the socket in a passive mode ready to accept connections. Only servers use listen. In addition to placing a protocol in passive mode, listen contains an argument that configures the size of a queue for incoming re- quests. A call has the form:
listen(descriptor, qlength);
Argument descriptor gives the descriptor of a socket that should be prepared for use by a server, and argument qlength specifies the length of the request queue for that socket.
9. Infinite loop
for ( ; ; ) {
. . .
}
10. Store the client’s address and socket descriptor by accepting an incoming connection.
len = sizeof(cliaddr);
connfd = accept(listenfd, (SA *) &cliaddr, &len);
Once a socket has been established, the server needs to wait for a connection. To do so, the server calls function accept. A call to accept blocks until a new connection request arrives. The call has the form:
newsock = accept(descriptor, addr, addrlen)
11. Sending data through a socket.
ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
write(connfd, buff, strlen(buff));
This calculate current time and send it to client through socket.
12. Terminate the connection.
close(connfd);
Client Side Code
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#define MAXLINE 1024
#define LISTENQ 10
typedef struct sockaddr SA;
int main (int argc, char **argv){
int sockfd, n;
char recvline [MAXLINE + 1];
struct sockaddr_in servaddr;
int port;
if(argc != 3){
printf("Usage: a.out <IPaddress> <port no.>");
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){ // Creates a TCP Socket
printf("Socket Error");
}
port = atoi(argv[2]); // ascii to integer conversion
bzero(&servaddr, sizeof(servaddr)); // fills servaddr with zeros.
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0){
// pton = presentatin to network
printf("inet_pton error for %s", argv[1]);
}
if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0){
// Establishes a TCP Connnection
printf("Connect Error.\n");
}
while ((n=read(sockfd, recvline, MAXLINE)) > 0){
// reads server reply.
recvline[n] =0;
if (fputs(recvline, stdout) == EOF){
printf("fputs error.\n");
}
}
if (n <0){
printf("read error");
}
}
Instructions for Lab 1
- Create two files for the Client and server program named as daytimetcpserver.c and daytimetcpclient.c
- Write a server and client program
- Save both files in the same directory
- Compile both programs using GCC compiler.
example: gcc -o server daytimetcpserver.c (It creates an output file server)
do similar for client program
- Open terminal and run server program
example: ./server <portno> (Specify port number)
6: In another terminal run client program
example: ./client <server ip> <port no> (Specify server ip and port no)
- Observer an output.
- Submit your code