Here's a simple Go-Back-N ARQ implementation using C socket programming to simulate communication between a client (sender) and a server (receiver).
Overview:
- Go-Back-N ARQ allows the sender to send multiple packets (window size) without waiting for individual ACKs.
- If a packet is lost or an ACK is not received, all packets starting from the lost packet are retransmitted.
- The server randomly simulates ACK loss or successful reception.
Program Structure:
- Server: Simulates ACK reception with a chance of ACK loss, acknowledging packets up to the first lost packet.
- Client: Sends packets in a sliding window fashion, retransmitting the entire window if an ACK is lost.
Server - Receiver
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <time.h>
#define PORT 8080
#define BUFFER_SIZE 1024
#define LOSS_PROBABILITY 30 // 30% chance of ACK loss
int main() {
int server_fd, new_socket;
struct sockaddr_in address;
int addrlen = sizeof(address);
char buffer[BUFFER_SIZE] = {0};
int ack;
srand(time(0)); // Random seed for ACK simulation
// Create socket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
// Bind socket
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
perror("Bind failed");
exit(EXIT_FAILURE);
}
// Listen for client
if (listen(server_fd, 3) < 0) {
perror("Listen failed");
exit(EXIT_FAILURE);
}
printf("Server: Waiting for connection...\n");
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
perror("Accept failed");
exit(EXIT_FAILURE);
}
printf("Server: Connection established.\n");
while (1) {
memset(buffer, 0, BUFFER_SIZE);
int valread = read(new_socket, buffer, BUFFER_SIZE);
if (valread == 0) break;
ack = atoi(buffer);
printf("Server: Received packet %d\n", ack);
// Simulate ACK loss
if (rand() % 100 < LOSS_PROBABILITY) {
printf("Server: ACK for packet %d lost!\n\n", ack);
} else {
sleep(1); // Simulate processing delay
printf("Server: ACK sent for packet %d\n\n", ack);
memset(buffer,0,BUFFER_SIZE);
sprintf(buffer, "%d", ack); // Send ACK
send(new_socket, buffer, strlen(buffer)+1, 0);
}
}
close(new_socket);
close(server_fd);
return 0;
}
Client - Sender
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/time.h>
#define PORT 8080
#define BUFFER_SIZE 1024
#define TIMEOUT 3 // Timeout in seconds
#define WINDOW_SIZE 4 // Sliding window size
#define TOTAL_PACKETS 10 // Number of packets to send
int main() {
int sock = 0;
struct sockaddr_in serv_addr;
char buffer[BUFFER_SIZE] = {0};
struct timeval tv;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
perror("Invalid address/ Address not supported");
exit(EXIT_FAILURE);
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
perror("Connection failed");
exit(EXIT_FAILURE);
}
printf("Client: Connected to server.\n");
tv.tv_sec = TIMEOUT;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
int base = 1;
int next_to_send = 1;
int ack, packets_acked = 0;
while (packets_acked < TOTAL_PACKETS) {
// Send all packets in the window
while (next_to_send < base + WINDOW_SIZE && next_to_send <= TOTAL_PACKETS) {
memset(buffer,0,BUFFER_SIZE);
printf("Client: Sending packet %d\n", next_to_send);
sprintf(buffer, "%d", next_to_send);
send(sock, buffer, strlen(buffer)+1, 0);
next_to_send++;
}
// Wait for ACK
memset(buffer, 0, BUFFER_SIZE);
int valread = read(sock, buffer, BUFFER_SIZE);
if (valread > 0) {
ack = atoi(buffer);
printf("Client: ACK received for packet %d\n", ack);
// Slide the window if ACK corresponds to the base
if (ack == base) {
base = ack + 1;
packets_acked = ack;
}
} else {
printf("Client: Timeout! Retransmitting from packet %d...\n", base);
next_to_send = base; // Reset next_to_send to base for retransmission
}
}
printf("Client: All packets sent successfully.\n");
close(sock);
return 0;
}
How to Run the Program:
- Compile the Server and Client
- Run the Server
- Run the Client (in a new terminal)
How It Works:
- Client sends packets in batches (window size of 4).
- If an ACK is not received within the timeout period, the client retransmits starting from the first unacknowledged packet.
- Server randomly decides to send ACKs or simulate ACK loss.
- This process continues until all packets are successfully acknowledged.
Testing Process:
- Run the server first.
- Run the client in a separate terminal.
- Observe the gradual packet transmission and retransmissions based on ACK loss.
Key Points:
- Sliding window approach for efficiency.
- Efficient retransmission by avoiding the need to retransmit all packets, only those starting from the missing ACK.
- Simulates real-world network issues like packet loss and retransmission.
Code Explanations - Receiver Server
1. Headers and Macros:
- Purpose: These headers provide necessary functions for socket programming and general operations.
stdio.h
– Standard I/O functions (printf
,perror
).stdlib.h
– For general utilities (exit
,atoi
,rand
).string.h
– For string handling (memset
,strlen
).unistd.h
– For system calls (read
,write
,close
).arpa/inet.h
– Socket-related functions (inet_addr
,sockaddr_in
).time.h
– For randomization (time
,srand
).
PORT
– The server listens on port 8080.BUFFER_SIZE
– Defines the size of the buffer used for sending/receiving data (1 KB).LOSS_PROBABILITY
– Simulates a 30% chance that the ACK will be "lost" (simulated by not sending an acknowledgment).
2. Variable Declarations:
server_fd
– File descriptor for the server socket.new_socket
– File descriptor for the client connection (afteraccept()
).address
– Stores server address information (IPv4, port, IP).addrlen
– Length of the address structure.buffer
– Temporary buffer for sending and receiving data.ack
– Packet number for which an acknowledgment (ACK) is sent.
3. Random Seed Initialization:
- Purpose: Initializes the random number generator for simulating packet loss.
srand(time(0))
– Seeds randomness based on the current time to ensure that every execution results in different ACK loss patterns.
4. Socket Creation:
socket(AF_INET, SOCK_STREAM, 0)
– Creates a TCP socket (SOCK_STREAM
indicates a stream-based connection).- Error Handling: If socket creation fails, an error is printed (
perror
), and the program exits.
5. Server Address Configuration:
sin_family
– Specifies the address family (AF_INET
for IPv4).sin_addr.s_addr
– Binds the server to listen on all available network interfaces (INADDR_ANY
).sin_port
– Converts the port number to network byte order (htons(PORT)
). This ensures compatibility across systems with different byte ordering.
6. Binding the Socket to the Address:
bind
– Binds the server socket to the specified IP and port.- Error Handling: If the bind fails (e.g., if the port is already in use), the server exits.
7. Listening for Incoming Connections:
listen
– Puts the server in a listening state for incoming connections.3
– Maximum number of pending connections in the queue.- Error Handling: If
listen
fails, the server exits.
8. Accepting Client Connections:
accept
– Waits for a client to connect. It blocks execution until a connection request arrives.new_socket
– A new socket for handling the specific client connection (different from the server socket).- Error Handling: If
accept
fails, the server exits.
9. Connection Established:
- Indicates that the client successfully connected.
10. Receiving and Sending ACKs:
while (1)
– Infinite loop to keep receiving packets until the client disconnects.memset
– Clears the buffer before each packet reception to avoid residual data.read
– Reads data from the client into the buffer.valread == 0
– If no data is received (client disconnects), the loop breaks.
11. Processing Received Packets:
atoi
– Converts the received packet number (in string format) to an integer.
12. Simulating ACK Loss:
rand() % 100 < 30
– Simulates ACK loss by generating a random number between 0 and 99. If the value falls below30
(30% chance), the ACK is "lost".- No ACK Sent: The server prints the loss message but does not send an acknowledgment.
13. Sending ACKs (if not lost):
sleep(1)
– Simulates network delay by pausing for 1 second before sending an ACK.sprintf
– Converts the integerack
to a string format for transmission.send
– Sends the ACK back to the client.
14. Closing Sockets:
close
– Closes both the client (new_socket
) and server (server_fd
) sockets to release resources.
Summary:
- The server accepts a connection from the client and continuously listens for incoming packets.
- For each packet received, it simulates ACK loss with a 30% probability.
- If ACK is not "lost," the server sends it back to the client after a small delay.
- This simulates the behavior of a Go-Back-N ARQ protocol where packets may need retransmission if ACKs are not received.
Code Explanations Sender - Client
1. Headers and Macros:
- Standard C Headers:
stdio.h
– For input/output functions (printf
,sprintf
).stdlib.h
– For general functions likeexit()
,atoi()
.string.h
– For string manipulation (strlen
,memset
).unistd.h
– For system calls (read
,write
,close
).arpa/inet.h
– For socket functions (inet_pton
,sockaddr_in
).sys/time.h
– For handling timeouts withsetsockopt()
.
- Macros:
PORT
– Defines the port number used for communication.BUFFER_SIZE
– Sets the buffer size for sending and receiving data.TIMEOUT
– Specifies how long the client will wait for an ACK before retransmitting.WINDOW_SIZE
– Number of packets that can be sent before waiting for ACKs.TOTAL_PACKETS
– Total number of packets to send.
2. Socket Creation and Connection:
- Socket Variables:
sock
– The socket descriptor.serv_addr
– Stores server address information.buffer
– Temporary buffer for sending and receiving data.tv
– Timeout structure for setting the socket read timeout.
- Create Socket:
socket(AF_INET, SOCK_STREAM, 0)
– Creates a TCP socket.AF_INET
– IPv4 address family.SOCK_STREAM
– Stream socket (TCP).perror
– Prints error if socket creation fails.
3. Server Address Setup:
- Configure Server Address:
sin_family
– Set toAF_INET
(IPv4).sin_port
– Converts the port to network byte order usinghtons()
.inet_pton
– Converts IP address (localhost127.0.0.1
) from text to binary.
4. Connect to Server:
- Establish Connection:
connect()
– Connects to the server using the specified address.- If the connection fails, an error message is displayed.
5. Set Timeout:
- Timeout Setup:
setsockopt
– Configures the socket to timeout if no data is received within 3 seconds (TIMEOUT
).
6. Sliding Window Variables:
- Sliding Window Variables:
base
– The first unacknowledged packet.next_to_send
– Tracks the next packet to be sent.ack
– Stores received ACKs.packets_acked
– Total packets acknowledged so far.
7. Sending Packets (Sliding Window):
- Send Packets Within Window:
while (next_to_send < base + WINDOW_SIZE)
– Send packets until the window is full.sprintf(buffer, "%d", next_to_send)
– Prepare packet number as a string.send()
– Send the packet to the server.- Increment
next_to_send
after each packet.
8. Wait for ACKs:
- ACK Handling (Loop Until Timeout):
read()
– Wait for the server to send an ACK.atoi(buffer)
– Convert received string to integer (ACK number).- If ACK is received, slide the window by adjusting
base
and incrementpackets_acked
. - Timeout Handling:
- If no ACK is received within 3 seconds, the client retransmits packets starting from the
base
.
- If no ACK is received within 3 seconds, the client retransmits packets starting from the
9. Completion:
- Completion Message:
- Once all packets are acknowledged, the client displays a success message and closes the socket.
How It Works:
Window-Based Transmission:
- Packets are sent in chunks (size of the window).
- The client waits for ACKs for the sent packets.
Timeouts and Retransmission:
- If an ACK is not received within 3 seconds, the client retransmits starting from the first unacknowledged packet (
base
).
- If an ACK is not received within 3 seconds, the client retransmits starting from the first unacknowledged packet (
Efficiency:
- Multiple packets can be sent before waiting for ACKs (Go-Back-N mechanism).
- The window slides forward when consecutive ACKs are received.
Key Concepts:
- Sliding Window: Allows multiple packets to be in-flight at once.
- Timeout & Retransmission: Ensures lost packets are resent.
- Go-Back-N ARQ: If a packet is lost, all packets from that point are retransmitted.
Comments
Post a Comment