Network programming Pt. 1 - TCP and Hello World!
Introduction
a short introduction to TCP and code walkthrough of a simple TCP web server.
TCP protocol
The Transmission Control Protocol (TCP) is one of the main protocols of the Internet protocol suite. It originated in the initial network implementation in which it complemented the Internet Protocol (IP). Therefore, the entire suite is commonly referred to as TCP/IP. TCP provides reliable, ordered, and error-checked delivery of a stream of octets (bytes) between applications running on hosts communicating via an IP network. Major internet applications such as the World Wide Web, email, remote administration, and file transfer rely on TCP, which is part of the Transport Layer of the TCP/IP suite. SSL/TLS often runs on top of TCP.
Source: Wikipedia
TCP is a streaming protocol whereas UDP is a connectionless protocol.
Code
the code explained here can be found in my NetworkProgramming GitHub repository.
Walkthrough
we need a bunch of header files that contain different functions and structures that we need.
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#define MAX_BACKLOG 10
#define PORT "8080"
Header Breakdown
| Header | what for? |
|---|---|
| sys/types.h | system types. used in cpmbination with sys/socket.h for compatibily on all unix-like systems. |
| sys/socket.h | socket(), bind(), connect(), accept(), send() etc.. |
| netinet/in.h | Internet address family - structures for IPV4 IPV6 etc. |
| netdb.h | getaddrinfo() getnameinfo() etc.. |

we start by calling init_server() function. this function will create a socket and bind it to a port.
init_server return’s a socket descriptor (> 0) if the socket is created and the address is successfully binded.
int socketfd = init_server();
if (socketfd < 0)
{
printf("cannot init_server()");
return 1;
}
this is our init_server() function.
int init_server()
{
struct addrinfo hints;
struct addrinfo *bind_addr;
memset(&hints, 0, sizeof(hints)); //zero out!
hints.ai_family = AF_INET; // we need ipv4
hints.ai_socktype = SOCK_STREAM; // TCP
hints.ai_flags = AI_PASSIVE; // PASSIVE mode
getaddrinfo(0, PORT, &hints, &bind_addr); //get local address from system.
//init socket
int socketfd = socket(bind_addr->ai_family, bind_addr->ai_socktype, bind_addr->ai_protocol);
if (bind(socketfd, bind_addr->ai_addr, bind_addr->ai_addrlen) == -1)
{
return -1;
}
return socketfd;
}
- we first start by declaring two structs of
addrinfo-hintsandbind_addr - we must zero out the struct struct
memset(). this will remove any garbage data from it and set all friends to0. - set fields in
hintsstruct. (refer to inline comments).
we only need to set hints.ai_socktype in a TCP client scenario. more on that in later parts.
- we then call
getaddrinfo(). it’s defined as:
int getaddrinfo(const char *node, const char *service,
const struct addrinfo *hints,
struct addrinfo **res);
set NULL as the first argument(node) indicating we need an address from system, 2nd arg. is our desired port, 3rd arg is hints struct passed as a ref, the result of this is stored in bind_addr struct that we defined above and passed as a ref as 4th arg.
we start a socket by passing the required parameters from
bind_addrstruct. it will return a negative number on failure. a positive number is returned on successful creation of socket, this number indicates the file descriptor associated with the socket.we call
bind(). this will bind the IP to port.bind()returns a negative number on failure.finally we return the
socket_fd
Back to main()
we then call listen() with two arguments, 1st arg is socket_fd and second one is MAX_BACKLOG - this is the maximum number of simultanious connection that our socket will accept before refusing.
//start listining
if (listen(socketfd, MAX_BACKLOG) >= 0)
{
printf("โ
server listining on 127.0.0.1:%s\n", PORT);
}
else
{
printf("โ cannot listen()! %d \n", listen(socketfd, MAX_BACKLOG));
}
we then call to accept_and_send() function with socket_fd as arg. this function will accept incoming connections (forwarded by listen())
while (true)
{
accept_and_send(socketfd);
}
return 0;
accept_and_send() function:
int accept_and_send(int socketfd)
{
struct sockaddr_storage client_addr; //to store client addr
socklen_t client_addr_len; //length of client addr;
int client = accept(socketfd, (struct sockaddr *)&client_addr, &client_addr_len);
if (client == -1)
{
printf("cannot accept connection from client!\n");
return -1;
}
char addr_buffer[100]; //empty buf. to store ip.
getnameinfo((struct sockaddr *)&client_addr, client_addr_len, addr_buffer, sizeof(addr_buffer), 0, 0, NI_NUMERICHOST);
printf("client IP: %s\n", addr_buffer);
// HANDLE / READ REQ
char request[1024];
int bytes_received = recv(client, request, 1024, 0);
//send response
const char *response = "HTTP/1.1 200 OK\r\n"
"Connection: close\r\n"
"Content-Type: text/plain\r\n\r\n"
"Hello World from hello.c";
int bytes_sent = send(client, response, strlen(response), 0);
close(client);
}
we start the function by declaring two structs -
client_addrandclient_addr_lensockaddr_storagestores the client address.client_addr_lenstores lenth of client address.we call
accept(). this will accept the client connection and store the details in above-declared structs.it returns-1on failure. this returns a file descriptor for the accepted socket that we can use to send and receive data from the client.
optionally, we can get ip address of client using getnameinfo(). getnameinfo() is essentially inverse of getaddrinfo().
TCP connection is initiated by receiving data from the client. this acts as a handshake between client and server.
we can then send data to the client, we use
send(). to send data to the client.close the connection by closing the client file descriptor.
it’s always a good practice to close socket at end of program.
close(socket_fd)
Let’s test it out!
compile the program using gcc
gcc hello.c -o hello
Run the program
~/Documents/Projects/network_programming ยป ./hello
socketfd = 3
โ
server listining on 127.0.0.1:8080
open a browser and navigate to http://127.0.0.1:8080/
you should see a nice message from our webserver:
Hello World from hello.c
Conclusion
My humble attempt to re-explain network programming concepts and code in C as I learn them myself, I hope this series helps in your learning and also serves as a note-keeping for me ๐