/* Please help me with this, will UPVOTE! */ In C, TASK: To build a Stop and Wait reliable protocol on top of UDP to p
Posted: Sun May 15, 2022 8:14 am
/* Please help me with this, will UPVOTE! */
In C,
TASK: To build a Stop and Wait
reliable protocol on top of UDP to provide a reliable transport
service while
considering loss.
TFv3 – Stop and Wait for an Unreliable Channel, with Loss
In this lab, you will extend the protocol to examine also the
loss of a packet and/or an ACK. This version of file transfer is
then TFv3.
TFv3 implements basically the protocol rdt3.0 presented in the
textbook. The FMS of the sender is shown below.
Communication is unidirectional, i.e., data flows from the client
to the server. The server starts first and waits for
messages. The client starts the communication. Messages have
sequence or ack number 0 or 1 (start with zero).
Before sending each message, a checksum is calculated and added to
the header.
After sending each message, the client starts a timer, using
select(). If the return of select() is zero, there is
no data, and the client needs to retransmit, restart the timer, and
call select again. If select returns non-zero, there
is data, so the client calls recvfrom() to receive the ACK and then
processes it. If the ACK is not corrupted and
the ACK number is right, the client can now send the next
message.
After receiving each message, the server checks its checksum. If
the message is correct and the seq number is
right, the server sends an ACK message with the right seq number,
and the data is ready to be written to the file.
Otherwise, the server repeats the last ACK message and waits to
receive a message again. You only need to simulate a drop of
ACK.
To verify your protocol, use the result of a random function to
decide to send or skip a message, to decide to send
or skip an ACK message (only change to the server), and to decide
whether to send the right checksum or just
zero. This will fake the error and loss effect.
This is an example on how to use select( ):
// local variables needed
struct timeval tv; // timer
int rv; // select returned value
// set up reads file descriptor at the beginning of the function to
be checked
for being ready to read
fd_set readfds;
fcntl (sock, F_SETFL, O_NONBLOCK);
...
// start before calling select
FD_ZERO (&readfds); //initializes readfds to have zero
bits
FD_SET (sock, &readfds); //sets readfds bit
// set the timer
tv.tv_sec = 1;
tv.tv_usec = 0;
// call select () which returns the number of ready descriptors
that are
contained in the bit masks.
// if the time limit expires, select returns zero and sets
errno
rv = select (sock + 1, &readfds, NULL, NULL, &tv);
if (rv == 0)
{
// timeout, no data
}
else if (rv == 1)
{
// there is data to be received
}
Important note
The server closes the file and terminates execution after the
message with zero bytes arrives. If the ACK sent for
that last message does not make it to the client, the client will
keep resending it forever to a non-responding
server. To avoid that, the client will start a counter after
sending a message with zero bytes and will only resend
that last message 3 times. After 3 times, it will return to the
main function.
Template Code for client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
//Declare a Header structure that holds, sequence/ acknowledgement
number,
checksum, and length of a packet
typedef struct {
int seq_ack;
int len;
int cksum;
} Header;
//Declare a packet structure that holds data and header
typedef struct {
Header header;
char data[10];
} Packet;
//Calculate the Checksum
int getChecksum(Packet packet) {
packet.header.cksum = 0;
int checksum = 0;
char *ptr = (char *)&packet;
char *end = ptr + sizeof(Header) + packet.header.len;
while (ptr < end) {
checksum ^= *ptr++;
}
return checksum;
}
//Print received packet
void printPacket(Packet packet) {
printf("Packet{ header: { seq_ack: %d, len: %d, cksum: %d }, data:
\"",
packet.header.seq_ack,
packet.header.len,
packet.header.cksum);
fwrite(packet.data, (size_t)packet.header.len, 1, stdout);
printf("\" }\n");
}
//client sending packet with checksum and sequence number, waits
for
acknowledgement, and sets up a time
void clientSend(int sockfd, const struct sockaddr *address,
socklen_t addrlen,
Packet packet, unsigned retries) {
while (1) {
//if retries is greater than 3, we give up and move on
if(retries >= 3){
break;
}
//calculate checksum of packet
//Simulate loss of a packet
if(rand() % 5 == 0) //simulate a drop of packet (probability =
20%)
printf("Dropping packet\n");
else{
//send the packet
printf("Client sending packet\n");
sendto(sockfd, &packet, sizeof(packet), 0, address,
addrlen);
}
// wait until an ACK is received or timeout using select
statement
// local variables needed
struct timeval tv; // timer
tv.tv_sec = 1;
tv.tv_usec = 0;
int rv; // select returned value
// set up reads file descriptor at the beginning of the function to
be
checked for being ready to read
fd_set readfds;
fcntl (sockfd, F_SETFL, O_NONBLOCK);
// start before calling select
FD_ZERO (&readfds); //initializes readfds to have zero
bits
FD_SET (sockfd, &readfds); //sets readfds bit
//call select
if( rv == 0){
printf("Timeout\n");
//increment retries if packet is dropped
retries++;
}
//so, there is an ACK to receive
else{
//receive an ACK from the server
//print received packet (ACK) and checksum
printf("Client received ACK %d, checksum %d - \n",
recvpacket.header.seq_ack, recvpacket.header.cksum);
//calculate checksum of received packet (ACK)
//check the checksum
//if bad checksum, resend packet
printf("Client: Bad checksum, expected checksum was: %d\n",
e_cksum);
//check the sequence number
//if incorrect sequence number, resend packet
printf("Client: Bad seqnum, expected sequence number was: %d\
n",packet.header.seq_ack);
//if the ckechsum and sequence numbers are correct, break and
return to
the main to get the next packet to send
} else {
//good ACK, we're done
printf("Client: Good ACK\n");
break;
}
}
}
}
int main(int argc, char *argv[]) {
//Get from the command line, server IP, Port and src file
if (argc != 4) {
printf("Usage: %s <ip> <port> <srcfile>\n",
argv[0]);
exit(0);
}
//Declare socket file descriptor.
int sockfd;
//Open a UDP socket, if successful, returns a descriptor
//Declare server address to connect to
struct sockaddr_in servAddr;
struct hostent *host;
host = (struct hostent *) gethostbyname(argv[1]);
///Set the server address to send using socket addressing
structure
memset(&servAddr, 0, sizeof(servAddr));
//initialize servAddr structure
//Open file using argv[3]
int fp = open(argv[3], O_RDWR);
if(fp < 0){
perror("Failed to open file\n");
exit(1);
}
//Send file contents to server packet by packet
int seq = 0;
socklen_t addr_len = sizeof(servAddr);
Packet packet;
int bytes;
while((bytes = read(fp, packet.data, sizeof(packet.data))) >
0){
//assign seq and checksum to packet and send
packet.header.seq_ack=seq;
packet.header.len=bytes;
packet.header.cksum=getChecksum(packet);
clientSend(sockfd,(struct sockaddr *)&servAddr,addr_len,
packet, 0);
//retries = 0
seq=(seq+1)%2;
}
//Send zero-length packet to server to end connection
Packet final;
final.header.seq_ack=seq;
final.header.len=0;
final.header.cksum=getChecksum(final);
clientSend(sockfd,(struct sockaddr *)&servAddr,addr_len,final,
0);
//Close file and socket
close(fp);
close(sockfd);
return 0;
}
In C,
TASK: To build a Stop and Wait
reliable protocol on top of UDP to provide a reliable transport
service while
considering loss.
TFv3 – Stop and Wait for an Unreliable Channel, with Loss
In this lab, you will extend the protocol to examine also the
loss of a packet and/or an ACK. This version of file transfer is
then TFv3.
TFv3 implements basically the protocol rdt3.0 presented in the
textbook. The FMS of the sender is shown below.
Communication is unidirectional, i.e., data flows from the client
to the server. The server starts first and waits for
messages. The client starts the communication. Messages have
sequence or ack number 0 or 1 (start with zero).
Before sending each message, a checksum is calculated and added to
the header.
After sending each message, the client starts a timer, using
select(). If the return of select() is zero, there is
no data, and the client needs to retransmit, restart the timer, and
call select again. If select returns non-zero, there
is data, so the client calls recvfrom() to receive the ACK and then
processes it. If the ACK is not corrupted and
the ACK number is right, the client can now send the next
message.
After receiving each message, the server checks its checksum. If
the message is correct and the seq number is
right, the server sends an ACK message with the right seq number,
and the data is ready to be written to the file.
Otherwise, the server repeats the last ACK message and waits to
receive a message again. You only need to simulate a drop of
ACK.
To verify your protocol, use the result of a random function to
decide to send or skip a message, to decide to send
or skip an ACK message (only change to the server), and to decide
whether to send the right checksum or just
zero. This will fake the error and loss effect.
This is an example on how to use select( ):
// local variables needed
struct timeval tv; // timer
int rv; // select returned value
// set up reads file descriptor at the beginning of the function to
be checked
for being ready to read
fd_set readfds;
fcntl (sock, F_SETFL, O_NONBLOCK);
...
// start before calling select
FD_ZERO (&readfds); //initializes readfds to have zero
bits
FD_SET (sock, &readfds); //sets readfds bit
// set the timer
tv.tv_sec = 1;
tv.tv_usec = 0;
// call select () which returns the number of ready descriptors
that are
contained in the bit masks.
// if the time limit expires, select returns zero and sets
errno
rv = select (sock + 1, &readfds, NULL, NULL, &tv);
if (rv == 0)
{
// timeout, no data
}
else if (rv == 1)
{
// there is data to be received
}
Important note
The server closes the file and terminates execution after the
message with zero bytes arrives. If the ACK sent for
that last message does not make it to the client, the client will
keep resending it forever to a non-responding
server. To avoid that, the client will start a counter after
sending a message with zero bytes and will only resend
that last message 3 times. After 3 times, it will return to the
main function.
Template Code for client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/select.h>
//Declare a Header structure that holds, sequence/ acknowledgement
number,
checksum, and length of a packet
typedef struct {
int seq_ack;
int len;
int cksum;
} Header;
//Declare a packet structure that holds data and header
typedef struct {
Header header;
char data[10];
} Packet;
//Calculate the Checksum
int getChecksum(Packet packet) {
packet.header.cksum = 0;
int checksum = 0;
char *ptr = (char *)&packet;
char *end = ptr + sizeof(Header) + packet.header.len;
while (ptr < end) {
checksum ^= *ptr++;
}
return checksum;
}
//Print received packet
void printPacket(Packet packet) {
printf("Packet{ header: { seq_ack: %d, len: %d, cksum: %d }, data:
\"",
packet.header.seq_ack,
packet.header.len,
packet.header.cksum);
fwrite(packet.data, (size_t)packet.header.len, 1, stdout);
printf("\" }\n");
}
//client sending packet with checksum and sequence number, waits
for
acknowledgement, and sets up a time
void clientSend(int sockfd, const struct sockaddr *address,
socklen_t addrlen,
Packet packet, unsigned retries) {
while (1) {
//if retries is greater than 3, we give up and move on
if(retries >= 3){
break;
}
//calculate checksum of packet
//Simulate loss of a packet
if(rand() % 5 == 0) //simulate a drop of packet (probability =
20%)
printf("Dropping packet\n");
else{
//send the packet
printf("Client sending packet\n");
sendto(sockfd, &packet, sizeof(packet), 0, address,
addrlen);
}
// wait until an ACK is received or timeout using select
statement
// local variables needed
struct timeval tv; // timer
tv.tv_sec = 1;
tv.tv_usec = 0;
int rv; // select returned value
// set up reads file descriptor at the beginning of the function to
be
checked for being ready to read
fd_set readfds;
fcntl (sockfd, F_SETFL, O_NONBLOCK);
// start before calling select
FD_ZERO (&readfds); //initializes readfds to have zero
bits
FD_SET (sockfd, &readfds); //sets readfds bit
//call select
if( rv == 0){
printf("Timeout\n");
//increment retries if packet is dropped
retries++;
}
//so, there is an ACK to receive
else{
//receive an ACK from the server
//print received packet (ACK) and checksum
printf("Client received ACK %d, checksum %d - \n",
recvpacket.header.seq_ack, recvpacket.header.cksum);
//calculate checksum of received packet (ACK)
//check the checksum
//if bad checksum, resend packet
printf("Client: Bad checksum, expected checksum was: %d\n",
e_cksum);
//check the sequence number
//if incorrect sequence number, resend packet
printf("Client: Bad seqnum, expected sequence number was: %d\
n",packet.header.seq_ack);
//if the ckechsum and sequence numbers are correct, break and
return to
the main to get the next packet to send
} else {
//good ACK, we're done
printf("Client: Good ACK\n");
break;
}
}
}
}
int main(int argc, char *argv[]) {
//Get from the command line, server IP, Port and src file
if (argc != 4) {
printf("Usage: %s <ip> <port> <srcfile>\n",
argv[0]);
exit(0);
}
//Declare socket file descriptor.
int sockfd;
//Open a UDP socket, if successful, returns a descriptor
//Declare server address to connect to
struct sockaddr_in servAddr;
struct hostent *host;
host = (struct hostent *) gethostbyname(argv[1]);
///Set the server address to send using socket addressing
structure
memset(&servAddr, 0, sizeof(servAddr));
//initialize servAddr structure
//Open file using argv[3]
int fp = open(argv[3], O_RDWR);
if(fp < 0){
perror("Failed to open file\n");
exit(1);
}
//Send file contents to server packet by packet
int seq = 0;
socklen_t addr_len = sizeof(servAddr);
Packet packet;
int bytes;
while((bytes = read(fp, packet.data, sizeof(packet.data))) >
0){
//assign seq and checksum to packet and send
packet.header.seq_ack=seq;
packet.header.len=bytes;
packet.header.cksum=getChecksum(packet);
clientSend(sockfd,(struct sockaddr *)&servAddr,addr_len,
packet, 0);
//retries = 0
seq=(seq+1)%2;
}
//Send zero-length packet to server to end connection
Packet final;
final.header.seq_ack=seq;
final.header.len=0;
final.header.cksum=getChecksum(final);
clientSend(sockfd,(struct sockaddr *)&servAddr,addr_len,final,
0);
//Close file and socket
close(fp);
close(sockfd);
return 0;
}