So here is a pair of programs demonstrating the use of sockets on Linux. The server program is run first. Then whenever the client program is run, it connects to the server on the specified port and they both exchange strings and terminate. TCP is used over IPv4.
Simple_tcpserver_ipv4.c:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> void error(char *msg) { perror(msg); exit(1); } int main(int argc, char *argv[]) { int sockfd, newsockfd, portno; socklen_t clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n; if (argc < 2) { fprintf(stderr, "Usage: %s\n", argv[0]); exit(0); } printf("\nIPv4 TCP Server Started...\n"); //Sockets Layer Call: socket() sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); //Sockets Layer Call: bind() if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding"); //Sockets Layer Call: listen() listen(sockfd, 5); clilen = sizeof(cli_addr); //Sockets Layer Call: accept() newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) error("ERROR on accept"); //Sockets Layer Call: inet_ntoa() printf("Incoming connection from client having IPv4 address: %s\n", inet_ntoa(cli_addr.sin_addr)); memset(buffer,0, 256); //Sockets Layer Call: recv() n = recv(newsockfd, buffer, 255, 0); if (n < 0) error("ERROR reading from socket"); printf("Message from client: %s\n", buffer); //Sockets Layer Call: send() n = send(newsockfd, "Server got your message", 23+1, 0); if (n < 0) error("ERROR writing to socket"); //Sockets Layer Call: close() close(sockfd); close(newsockfd); return 0; }
Simple_tcpclient_ipv4.c:
Makefile_tcpipv4:#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> void error(char *msg) { perror(msg); exit(0); } int main(int argc, char *argv[]) { int sockfd, portno, n; struct sockaddr_in serv_addr; struct hostent *server; char buffer[256] = "This is a string from client!"; if (argc < 3) { fprintf(stderr, "Usage: %s\n", argv[0]); exit(0); } portno = atoi(argv[2]); printf("\nIPv4 TCP Client Started...\n"); //Sockets Layer Call: socket() sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); //Sockets Layer Call: gethostbyname() server = gethostbyname(argv[1]); if (server == NULL) { fprintf(stderr, "ERROR, no such host\n"); exit(0); } memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; memmove((char *) &serv_addr.sin_addr.s_addr, (char *) server->h_addr, server->h_length); serv_addr.sin_port = htons(portno); //Sockets Layer Call: connect() if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR connecting"); //Sockets Layer Call: send() n = send(sockfd,buffer, strlen(buffer)+1, 0); if (n < 0) error("ERROR writing to socket"); memset(buffer, 0, 256); //Sockets Layer Call: recv() n = recv(sockfd, buffer, 255, 0); if (n < 0) error("ERROR reading from socket"); printf("Message from server: %s\n", buffer); //Sockets Layer Call: close() close(sockfd); return 0; }
all: gcc Simple_tcpserver_ipv4.c -o Simple_tcpserver_ipv4.out gcc Simple_tcpclient_ipv4.c -o Simple_tcpclient_ipv4.out clean: rm Simple_tcpserver_ipv4.out rm Simple_tcpclient_ipv4.out
Execution results on Ubuntu:

In the above screenshot, I have shown both the client and server applications running on the same PC and so while running the client application, we use the local loopback address 127.0.0.1.
Now if we need to port the above pair of applications from IPv4 to IPv6, we need to make subtle changes in the code. When such changes are made to the above pair of applications, they would look as below. Changes are highlighted in red.
Simple_tcpserver_ipv6.c:
Simple_tcpclient_ipv6.c:#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> void error(char *msg) { perror(msg); exit(1); } int main(int argc, char *argv[]) { int sockfd, newsockfd, portno; socklen_t clilen; char buffer[256]; struct sockaddr_in6 serv_addr, cli_addr; int n; char client_addr_ipv6[100]; if (argc < 2) { fprintf(stderr, "Usage: %s\n", argv[0]); exit(0); } printf("\nIPv6 TCP Server Started...\n"); //Sockets Layer Call: socket() sockfd = socket(AF_INET6, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin6_flowinfo = 0; serv_addr.sin6_family = AF_INET6; serv_addr.sin6_addr = in6addr_any; serv_addr.sin6_port = htons(portno); //Sockets Layer Call: bind() if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding"); //Sockets Layer Call: listen() listen(sockfd, 5); clilen = sizeof(cli_addr); //Sockets Layer Call: accept() newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) error("ERROR on accept"); //Sockets Layer Call: inet_ntop() inet_ntop(AF_INET6, &(cli_addr.sin6_addr),client_addr_ipv6, 100); printf("Incoming connection from client having IPv6 address: %s\n",client_addr_ipv6); memset(buffer,0, 256); //Sockets Layer Call: recv() n = recv(newsockfd, buffer, 255, 0); if (n < 0) error("ERROR reading from socket"); printf("Message from client: %s\n", buffer); //Sockets Layer Call: send() n = send(newsockfd, "Server got your message", 23+1, 0); if (n < 0) error("ERROR writing to socket"); //Sockets Layer Call: close() close(sockfd); close(newsockfd); return 0; }
Makefile_tcpipv6:#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> void error(char *msg) { perror(msg); exit(0); } int main(int argc, char *argv[]) { int sockfd, portno, n; struct sockaddr_in6 serv_addr; struct hostent *server; char buffer[256] = "This is a string from client!"; if (argc < 3) { fprintf(stderr, "Usage: %s\n", argv[0]); exit(0); } portno = atoi(argv[2]); printf("\nIPv6 TCP Client Started...\n"); //Sockets Layer Call: socket() sockfd = socket(AF_INET6, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); //Sockets Layer Call: gethostbyname2() server = gethostbyname2(argv[1],AF_INET6); if (server == NULL) { fprintf(stderr, "ERROR, no such host\n"); exit(0); } memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin6_flowinfo = 0; serv_addr.sin6_family = AF_INET6; memmove((char *) &serv_addr.sin6_addr.s6_addr, (char *) server->h_addr, server->h_length); serv_addr.sin6_port = htons(portno); //Sockets Layer Call: connect() if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR connecting"); //Sockets Layer Call: send() n = send(sockfd,buffer, strlen(buffer)+1, 0); if (n < 0) error("ERROR writing to socket"); memset(buffer, 0, 256); //Sockets Layer Call: recv() n = recv(sockfd, buffer, 255, 0); if (n < 0) error("ERROR reading from socket"); printf("Message from server: %s\n", buffer); //Sockets Layer Call: close() close(sockfd); return 0; }
all: gcc Simple_tcpserver_ipv6.c -o Simple_tcpserver_ipv6.out gcc Simple_tcpclient_ipv6.c -o Simple_tcpclient_ipv6.out clean: rm Simple_tcpserver_ipv6.out rm Simple_tcpclient_ipv6.out
Execution results on Ubuntu:
Source code(s):
Archive containing the above files can be downloaded from here.
Here is another version of the code which uses UDP instead of TCP. uses recvfrom() and sendto(). In this case only the client sends the string to server - the server does not send a string back.
Here is the source code for another pair of applications which implement a sort of chat server and its chat clients. Multiple chat clients can connect to a single chat server. Whatever string one client sends to the server, it is forwarded to all the clients. select() is used. The archive contains both IPv4 as well as IPv6 implementations.
Note: If you are going to be using link local IPv6 addresses with above sample applications, make sure to set serv_addr.sin6_scope_id = 0,1,2,3...(whatever is the interface number of your network adapter) in the client code. Read more here.
References:
Archive containing the above files can be downloaded from here.
Here is another version of the code which uses UDP instead of TCP. uses recvfrom() and sendto(). In this case only the client sends the string to server - the server does not send a string back.
Here is the source code for another pair of applications which implement a sort of chat server and its chat clients. Multiple chat clients can connect to a single chat server. Whatever string one client sends to the server, it is forwarded to all the clients. select() is used. The archive contains both IPv4 as well as IPv6 implementations.
Note: If you are going to be using link local IPv6 addresses with above sample applications, make sure to set serv_addr.sin6_scope_id = 0,1,2,3...(whatever is the interface number of your network adapter) in the client code. Read more here.
References:
- The above codes are based on:
- Writing a simple IPv6 program
- Example: Accepting connections from both IPv6 and IPv4 clients
- Porting applications to IPv6 HowTo
- Online syntax highlighting for "C" - for coloring the C code before pasting here!