6 minute read

a network packet is a formatted unit of data carried by a packet-switched network. A packet consists of control information and user data; the latter is also known as the payload. Control information provides data for delivering the payload.

  • TCP (Transmission Control Protocol) is a standard that defines how to establish and maintain a network conversation through which application programs can exchange data. TCP works with the Internet Protocol (IP), which defines how computers send packets of data to each other.

  • Packet loss occurs when one or more packets of data travelling across a computer network fail to reach their destination. Packet loss is either caused by errors in data transmission, typically across wireless networks, or network congestion.

  • TCP uses a network congestion-avoidance algorithm that includes various aspects of an additive increase/multiplicative decrease scheme, along with other schemes including slow start and congestion window, to achieve congestion avoidance.

  • Reno: if three duplicate ACKs are received, Reno will perform a fast retransmit and skip the slow start phase by instead halving the congestion window, setting the slow start threshold equal to the new congestion window, and enter a phase called fast recovery.

  • Cubic: TCP CUBIC default in Linux, most popular TCP for popular Web servers.it’s increase TCP’s sending rate until packet loss occurs at some router’s output: the bottleneck link.

In this project I used these algorithms to measure how long it takes them to accurately detect the packet losses with creating sockets using TCP protocol and CC algorithms in c language. I also used ‘tc’ (Traffic Control) to packet loss of 10%, 15%, 20%, 25% and 30% by sending a 1MB file and here are the results:

Packet Loss Cubic CC AVG Time Reno CC AVG Time
0% 1.002093 sec 1.002233 sec
10% 1.084104 sec 1.95328 sec
15% 1.084104 sec 3.182702 sec
20% 6.844125 sec 8.352214 sec
25% 18.392849 sec 14.452283 sec
30% 42.182998 sec 64.535568 sec

sender.c

#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <sys/stat.h>
#include <stdlib.h> 
#include <errno.h> 
#include <string.h> 
#include <arpa/inet.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/tcp.h> 

#define SERVER_PORT          5060
#define SERVER_IP_ADDRESS    "127.0.0.1"
#define FILENAME             "1mb.txt" 
#define FULL_SIZE 1048576
#define BUFF_SIZE 1500

int main() {

    /* INIT FIELDS
    * --> file_pointer == a pointer to the given file .
    * --> server_address == a structure describing an internet socket address.
    */    
    char buffer[BUFF_SIZE];
    int file_size;
    FILE *file_pointer;
    socklen_t length;

    int number_of_runs = 0;
    int i = 0;
    while(i < 2) {

        int j = 0;
        while(j < 5) {
            /* CREATE CLIENT SOCKET 
            * --> SOCK_STREAM == a TCP protocol type.
            */
            int client_socket = socket(AF_INET, SOCK_STREAM, 0);
            if(client_socket == -1) {
                fprintf(stderr, "Couldn't create the socket : %s\n", strerror(errno));
                exit(EXIT_FAILURE); // failing exit status.
            }

            /* CONGESTION CONTROL PROGRAM
            * --> getsockopt == function manipulates options associated with a socket.
            * --> setsockopt == function shall set the option specified by the option_name argument.
            * --> IPPROTO_TCP == to indicate that an option is interpreted by the TCP.
            * --> TCP_CONGESTION == Congestion control algorithm.
            */
            int get_sock_opt = getsockopt(client_socket, IPPROTO_TCP, TCP_CONGESTION, buffer, &length);
            if( get_sock_opt != 0) {
                perror("getsockopt");
                exit(EXIT_FAILURE); // failing exit status.
            }
            if(i == 0) {
                strcpy(buffer,"cubic");
            } else {
                strcpy(buffer,"reno");
            }
            length = sizeof(buffer);
            int set_sock_opt = setsockopt(client_socket, IPPROTO_TCP, TCP_CONGESTION, buffer, length);
            if(set_sock_opt !=0 ) {
                perror("setsockopt");
                exit(EXIT_FAILURE); // failing exit status.
            }
            get_sock_opt = getsockopt(client_socket, IPPROTO_TCP, TCP_CONGESTION, buffer, &length);
            if( get_sock_opt != 0) {
                perror("getsockopt");
                exit(EXIT_FAILURE); // failing exit status.
            }
            number_of_runs++;
            printf("\n======= (%d) Current CC: %s  ====== \n",number_of_runs, buffer);
            /* construct the server_address struct
            * --> memset == zeroing the server_address struct.
            * --> AF_INET == IPv4 type.
            * --> htons == short, network byte order converter.
            * --> inet_pton == convert the IP address from String type.
            */
            struct sockaddr_in server_address;
            memset(&server_address, 0, sizeof(server_address));
            server_address.sin_family = AF_INET;
            server_address.sin_port = htons(SERVER_PORT);
            int rval = inet_pton(AF_INET, (const char*)SERVER_IP_ADDRESS, &server_address.sin_addr);
            if(rval <= 0) {
                printf("inet_pton() failed");
                return -1;
            }

            /* CONNECT TO THE SERVER
            * --> make a connection to the server with client_socket.
            */
            int connection = connect(client_socket, (struct sockaddr *) &server_address, sizeof(server_address));
            if(connection == -1) {
                fprintf(stderr, "connect() failed with error code --> %s\n", strerror(errno));
                exit(EXIT_FAILURE); // failing exit status.
            } 
            else {
                printf("connected to server!\n");
            }

            /* SEND DATA TO SERVER */
            int numbytes = recv(client_socket, buffer, BUFF_SIZE, 0);
        	if (numbytes == -1) {
            		perror("recv");
            		exit(1);
		    }	

	        buffer[numbytes] = '\0';

        	printf("Received from server: '%s' \n", buffer);

            file_pointer = fopen(FILENAME, "r");
            if(file_pointer == NULL) {
                fprintf(stderr, "Failed to open file 1mb.txt : %s\n", strerror(errno));
                exit(EXIT_FAILURE);
            }

            int data_stream;
            int size = 0;
            while( ( data_stream = fread(buffer,1,sizeof(buffer),file_pointer) ) > 0 ) {
                size += send(client_socket, buffer, data_stream, 0);
            }

            if(size == FULL_SIZE) {
                printf("successfully sent 1MB file: %d\n",size);
            }else {
                printf("sadly sent just %d out of %d\n",size,FULL_SIZE);
            }
            sleep(1);
            close(client_socket);
            j++;
        }
        i++;
    }
    return 0;
}

Measure.c

#include <stdio.h>
#include <unistd.h> // for sleep()
#include <sys/types.h>
#include <sys/socket.h>
#include <time.h>    // for clock_t, clock()
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>

#define SERVER_PORT 5060  //The port that the server listens.
#define BILLION  1000000000.0
#define BUFF_SIZE 1500

int main() {
    // on linux to prevent crash on closing socket.
    signal(SIGPIPE, SIG_IGN);
    char buffer[BUFF_SIZE];

    // create a socket lisener.
    int socket_listener = -1;
    if((socket_listener = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
        printf("Couldn't create a socket listener : %d",errno);
    }

	// setsockopt = used to control the options of this socket.
    // Reuse the port if the server socket on was closed
	// and remains for 45 seconds in TIME-WAIT state till the final removal.
    int enable_reuse = 1;
    if(setsockopt(socket_listener, SOL_SOCKET, SO_REUSEADDR,&enable_reuse, sizeof(int)) < 0) {
        printf("setsockopt() failed with error code: %d", errno);
    }

    struct sockaddr_in server_address;
    memset(&server_address, 0, sizeof(server_address));

    server_address.sin_family = AF_INET;
    server_address.sin_addr.s_addr = INADDR_ANY;
    server_address.sin_port = htons(SERVER_PORT);  //network order

    // connect the server to a port which can read and write on.
    if(bind(socket_listener, (struct sockaddr *)&server_address, sizeof(server_address)) == -1) {
        printf("Bind failed with error code : %d" , errno);
        return -1;
    }

    printf("Bind() success!\n\n");

    // Make the socket listening; actually mother of all client sockets.
    // 500 is a Maximum size of queue connection requests
    // number of concurrent connections 
    if(listen(socket_listener, 500) == -1) {
        printf("listen() failed with error code : %d",errno);
        return -1;
    }

    //Accept and incoming connection
    printf("Waiting for incoming TCP-connections...\n");

    struct sockaddr_in client_address; 
    socklen_t client_address_length = sizeof(client_address);
    int i = 0;

    while(i < 2){
        int j = 0;
        double sum_for_average = 0.0;
        while(j < 5) {
            memset(&client_address, 0, sizeof(client_address));

            // updates the length in each iteration.
            client_address_length = sizeof(client_address);

            // accept() gets the connection and return the socket of this connection.
            int client_socket = accept(socket_listener, (struct sockaddr *)&client_address, &client_address_length);
            if(client_socket == -1) {
            printf("listen failed with error code : %d",errno);
            close(socket_listener);
            return -1;
            } else {
                printf("A new client connection accepted\n");
            }

            //Reply to client
            char message[] = "welcome";
            int messageLen = strlen(message) + 1;
            // this method returns the size of bytes that succesfully sent.
            int bytes_sent = send(client_socket, message, messageLen, 0);
            if(bytes_sent == -1) {
                printf("send() failed with error code : %d", errno); 
            }
            else if(bytes_sent == 0) {
                printf("peer has closed the TCP connection prior to send().\n");
            }
            else if (messageLen > bytes_sent) {
            printf("sent only %d bytes from the required %d.\n", messageLen, bytes_sent);
            }
            else {
            printf("'welcome' successfully sent.\n");            
            }

            struct timespec start, end;
            clock_gettime(CLOCK_REALTIME, &start);

            int bytes = -1;
            while(bytes != 0) {
                bytes = recv(client_socket,buffer, BUFF_SIZE,0);
            }
            clock_gettime(CLOCK_REALTIME, &end);
            // time_spent = end - start
            double time_spent = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / BILLION;
            printf("Time elpased is %f seconds\n\n", time_spent);
            sum_for_average += time_spent;
            sleep(1);
            j++;
        }
        char cc_type[20];
        if(i == 0) {
            strcpy(cc_type,"cubic");
        } else {
            strcpy(cc_type,"reno");
        }
        printf("\nAverage time for CC %s is %f .\n\n",cc_type,sum_for_average/5);
        i++;
    }
    
    close(socket_listener);
    return 0;
}

Leave a comment