Network Lab

Implementation of Go-Back-N ARQ Protocol Using UDP

To implement the Go-Back-N Automatic Repeat reQuest (ARQ) protocol using socket programming in C.


Algorithms

Client (Sender)

Step 1: Create Socket

  • Create a UDP socket using socket(AF_INET, SOCK_DGRAM, 0).
  • If socket creation fails, terminate the program.

Step 2: Define Server Address

  • Set the address family to AF_INET.
  • Set the port number to 5555.
  • Set the IP address to 127.0.0.1.

Step 3: Set Timeout

  • Set a receive timeout using setsockopt() to handle lost acknowledgements.

Step 4: Initialize Window Variables

  • Set window size N.
  • Initialize base = 0, next_seq_num = 0.

Step 5: Send Packets in Window

  • While next_seq_num < base + N and there are packets to send:
    • Send packet with sequence number next_seq_num.
    • Increment next_seq_num.

Step 6: Wait for Acknowledgement

  • Wait for ACK from the server using recvfrom().
  • If correct ACK is received for sequence number ack:
    • Update base = ack + 1 (Cumulative ACK).
  • If timeout occurs:
    • Resend all packets from base to next_seq_num - 1.

Step 7: Repeat

  • Repeat steps 5 and 6 until all packets are acknowledged.

Step 8: Close Socket

  • Close the client socket.

Server (Receiver)

Step 1: Create Socket

  • Create a UDP socket using socket(AF_INET, SOCK_DGRAM, 0).
  • If socket creation fails, terminate the program.

Step 2: Define Server Address

  • Set the address family to AF_INET.
  • Set the port number to 5555.
  • Set the IP address to 127.0.0.1.

Step 3: Bind Socket

  • Bind the socket to the specified IP address and port using bind().

Step 4: Receive Data Packet

  • Receive a data packet from the client using recvfrom().
  • Extract the sequence number.

Step 5: Check Sequence Number

  • If the received sequence number matches expected_seq:
    • Accept the packet.
    • Send ACK for expected_seq.
    • Increment expected_seq.
  • Otherwise:
    • Discard the packet (out of order).
    • Send ACK for expected_seq - 1 (ACK for last correctly received packet).

Step 6: Repeat Process

  • Continue receiving packets and sending acknowledgements.

Programs

Client

#include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/time.h> #include <unistd.h> #define TIMEOUT_VALUE 2 #define TOTAL_PACKETS 10 #define WINDOW_SIZE 4 int main() { char *ip = "127.0.0.1"; int port = 5555; int sockfd; struct sockaddr_in addr; char buffer[1024]; socklen_t addr_size; int base = 0; int next_seq_num = 0; int ack_count = 0; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket error"); exit(1); } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = inet_addr(ip); struct timeval timeout; timeout.tv_sec = TIMEOUT_VALUE; timeout.tv_usec = 0; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); while (ack_count < TOTAL_PACKETS) { // Send packets within window while (next_seq_num < base + WINDOW_SIZE && next_seq_num < TOTAL_PACKETS) { memset(buffer, 0, sizeof(buffer)); sprintf(buffer, "DATA:%d", next_seq_num); printf("[CLIENT] Sending DATA seq=%d\n", next_seq_num); sendto(sockfd, buffer, strlen(buffer) + 1, 0, (struct sockaddr *)&addr, sizeof(addr)); next_seq_num++; } // Wait for ACK addr_size = sizeof(addr); int rec = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&addr, &addr_size); if (rec < 0) { printf("[CLIENT] Timeout! Resending window from seq=%d\n", base); next_seq_num = base; // Go Back N } else { int ack; sscanf(buffer, "ACK:%d", &ack); printf("[CLIENT] Received ACK seq=%d\n", ack); if (ack >= base) { // Cumulative ACK ack_count += (ack - base + 1); base = ack + 1; } } } printf("[CLIENT] All packets sent and acknowledged.\n"); close(sockfd); return 0; }

Server

#include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <unistd.h> int main() { char *ip = "127.0.0.1"; int port = 5555; int sockfd; struct sockaddr_in server_addr, client_addr; char buffer[1024]; socklen_t addr_size; int expected_seq = 0; sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("socket error"); exit(1); } memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port); server_addr.sin_addr.s_addr = inet_addr(ip); if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) { perror("bind error"); exit(1); } printf("[SERVER] Go-Back-N ARQ Server running...\n"); while (1) { memset(buffer, 0, sizeof(buffer)); addr_size = sizeof(client_addr); recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &addr_size); int seq; sscanf(buffer, "DATA:%d", &seq); if (seq == expected_seq) { printf("[SERVER] Received DATA seq=%d (Accepted)\n", seq); // Simulate ACK Loss if (rand() % 5 != 0) { // 80% chance to send ACK memset(buffer, 0, sizeof(buffer)); sprintf(buffer, "ACK:%d", seq); sendto(sockfd, buffer, strlen(buffer) + 1, 0, (struct sockaddr *)&client_addr, sizeof(client_addr)); printf("[SERVER] Sent ACK seq=%d\n", seq); } else { printf("[SERVER] Simulated ACK Loss for seq=%d\n", seq); } expected_seq++; } else { printf("[SERVER] Received DATA seq=%d (Discarded, expected seq=%d)\n", seq, expected_seq); // Send ACK for the last correctly received packet if (expected_seq > 0) { memset(buffer, 0, sizeof(buffer)); sprintf(buffer, "ACK:%d", expected_seq - 1); sendto(sockfd, buffer, strlen(buffer) + 1, 0, (struct sockaddr *)&client_addr, sizeof(client_addr)); printf("[SERVER] Resent ACK seq=%d\n", expected_seq - 1); } } } close(sockfd); return 0; }