BSD Socket Programming

How Socket Works?

When two network nodes are trying to communicate each other, at layer 3 and 4, they can use socket to connect and exchange data using read/write method. It is a server-client model where server creates a listener socket and client tries to connect.

Steps in the Server Side:

Create Socket

int sockfd = socket(domain_name, com_type, protocol)


sockfd: socket descriptor, an integer (file descriptor)

domain_name: data type - integer, domain - AF_INET (IPv4 protocol) , AF_INET6 (IPv6 protocol)

com_type: 

1. SOCK_STREAM: TCP(reliable, connection oriented)

2. SOCK_DGRAM: UDP(unreliable, connection less)

protocol: For Internet Protocol(IP) :  0 which appears on protocol field in the IP header of a packet.

               int sockfd = socket(AF_INET, SOCK_STREAM, 0);

                if (sockfd == -1) {

                    perror("Unable to create Socket");

                    exit(1);

                }



Bind

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);


After creation of the socket, bind() function binds the socket to the address and port number specified in addr(custom data structure). In the example code, we bind the server to the ip address which is come from the input, hence we use INADDR_ANY to specify the IP address.

               // 4. Bind to Server Address

                if (bind(sockfd, (const struct sockaddr *) &nwServerAddr, sizeof(nwServerAddr)) == -1) {

                    perror("Unable to Bind");

                    exit(1);

                }


Listen

int listen(int sockfd, int listen_port);


It puts the server socket in a passive mode, where it waits for the client to approach the server to make a connection. The listen_port, defines the maximum length to which the queue of pending connections for sockfd may grow. If a connection request arrives when the queue is full, the client may receive an error with an indication of ECONNREFUSED.



                // 5. Listen Socket for incoming File

                if (listen(sockfd, LISTEN_PORT) == -1) {

                    perror("Error in Socket Listening");

                    exit(1);

                }




Accept

int new_fd = accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


It extracts the first connection request on the queue of pending connections for the listening socket, sockfd, creates a new connected socket, and returns a new file descriptor referring to that socket. At this point, connection is established between client and server, and they are ready to transfer data.

               // 6. Accept connection for concurrency number

                socklen_t adlen = sizeof(nwClientAddr);

                int cfd = accept(sockfd, (struct sockaddr *) &nwClientAddr, &adlen);

                if (cfd == -1) {

                    perror("Error in Accepting Connection for ");

                    exit(1);

                 }


Receive :

int recv(sockfd, buf, len, 0);


sockfd : Socket file descriptor which already connected with server listen port.

buf : character buffer which is suppose to send to server

len : buffer length


Server Source:

#include <unistd.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <sys/file.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <assert.h>

#include <time.h>


#define MAX_LENGTH_OF_SINGLE_LINE 4096


#define LISTEN_PORT 8050


#define SERVER_PORT 5080


#define BUFFER_SIZE 100000

#define MAX_NAME 1000


int main(int argc, char *argv[]) {

char *hello = "Hi, I'm server"; 

// 1. Create TCP Socket

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd == -1) {

perror("Unable to create Socket");

exit(1);

}


// 2. Setup information about client and server

struct sockaddr_in nwClientAddr, nwServerAddr;

memset(&nwServerAddr, 0, sizeof(nwServerAddr));


// 3. IP address should be IPv4

nwServerAddr.sin_family = AF_INET;

nwServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);

nwServerAddr.sin_port = htons(SERVER_PORT);


// 4. Bind to Server Address

if (bind(sockfd, (const struct sockaddr *) &nwServerAddr, sizeof(nwServerAddr)) == -1) {

perror("Unable to Bind");

exit(1);

}


// 5. Listen Socket for incoming File

if (listen(sockfd, LISTEN_PORT) == -1) {

perror("Error in Socket Listening");

exit(1);

}


// 6. Accept connection for concurrency number

socklen_t adlen = sizeof(nwClientAddr);

int cfd = accept(sockfd, (struct sockaddr *) &nwClientAddr, &adlen);

if (cfd == -1) {

perror("Error in Accepting Connection for ");

exit(1);

}

int val = 0;


char conString[MAX_NAME] = {0};

if (recv(cfd, conString, MAX_NAME,0) == -1) {

perror("Unable to receive message due to connection error");

exit(1);

}

char *numstr = basename(conString);

printf("Received From Client <--- : %s\n", numstr);


send(cfd , hello , strlen(hello) , 0 ); 

     printf("%s message is sent to client\n",hello);


close(cfd);

close(sockfd);

return 0;

}


Steps in the Client Side:

Create Socket

int sockfd = socket(domain_name, com_type, protocol)


sockfd: socket descriptor, an integer (File Descriptor)

domain_name: integer, communication domain e.g., AF_INET (IPv4 protocol) , AF_INET6 (IPv6 protocol)

com_type: 

1. SOCK_STREAM: TCP(reliable, connection oriented)

2. SOCK_DGRAM: UDP(unreliable, connectionless)

protocol: Protocol value for Internet Protocol(IP), which is 0. This is the same number which appears on protocol field in the IP header of a packet.

// 2. Create TCP Socket

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd < 0) {

perror("Unable to create Socket");

exit(1);

}

Connect

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);


The connect() system call connects the socket referred to by the file descriptor sockfd to the address specified by addr. Server’s address and port is specified in addr.

// 6. Client will connect after server bind

if (connect(sockfd, (const struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {

perror("Unable to Connect");

exit(1);

}


Send :

int send(sockfd, buf, len, 0);

sockfd : Socket file descriptor which already connected with server listen port.

buf : character buffer which is suppose to send to server

len : buffer length

char numberstring[] = "Hello, I'm client"; 

if (send(sockfd, numberstring, strlen(numberstring), 0) == -1) {

perror("Unable to send Concurrency");

exit(1);

}


Client Source:


#include <unistd.h>

#include <stdio.h>

#include <dirent.h>

#include <string.h>

#include <malloc.h>

#include <stdlib.h>

#include <libgen.h>

#include <arpa/inet.h>

#include <netinet/in.h>

#include <sys/socket.h>

#include <assert.h>


#define MAX_LENGTH_OF_SINGLE_LINE 4096

#define SERVER_PORT 5080

#define BUFFER_SIZE 100000

#define MAX_FILE_COUNT 1000

#define MAX_NAME 1000


// Utility functions for socket

void sockUtil(char *ipAddr) {


// 2. Create TCP Socket

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

if (sockfd < 0) {

perror("Unable to create Socket");

exit(1);

}


// 3. Setup information about server

struct sockaddr_in serverAddress;

memset(&serverAddress, 0, sizeof(serverAddress));


// 4. IP address should be IPv4

serverAddress.sin_family = AF_INET;

serverAddress.sin_port = htons(SERVER_PORT);


// 5. Check IP adddres and convert it with inet_pton

if (inet_pton(AF_INET, ipAddr, &serverAddress.sin_addr) < 0) {

perror("Conversion Error in IP Address");

exit(1);

}


// 6. Client will connect after server bind

if (connect(sockfd, (const struct sockaddr *) &serverAddress, sizeof(serverAddress)) < 0) {

perror("Unable to Connect");

exit(1);

}

 

char numberstring[] = "Hello, I'm client"; 


if (send(sockfd, numberstring, strlen(numberstring), 0) == -1) {

perror("Unable to send Concurrency");

exit(1);

}

printf("Message is sent to Server\n");


char conString[MAX_NAME] = {0};

if (recv(sockfd, conString, MAX_NAME,0) == -1) {

perror("Unable to receive message due to connection error");

exit(1);

}

char *numstr = basename(conString);

printf("Received From Server <--- : %s\n", numstr);


close(sockfd);


}


int main(int argc, char* argv[]) {

// 1. Check the parameters from command line argument

if (argc < 2) {

perror("IP address is missing");

exit(1);

}

sockUtil(argv[1]);

return 0;

}

Prepare

$ git clone https://github.com/arupcsedu/BSDSocketProgramming.git

$ cd BSDSocketProgramming 

Build and Run Server

$ cd BSDSocketProgramming/HelloSocket 

$ g++ Server.cpp -o Server

$ ./Server 

Build and Run Client

$ g++ Client.cpp -o Client

$ ./Client 127.0.0.1


Source code URL:

https://github.com/arupcsedu/BSDSocketProgramming