Reliable Data Transfer Protocol
Reliable Data Transfer Protocol
IMPLEMENTATION TIPS
Recall
Reliable Data Transfer Mechanisms:
Checksum
Timer
Sequence number
ACK
NAK
Window, pipelining
socket
door
TCP
send buffer
TCP
receive buffer
socket
door
Packet ->
application
writes data
application
reads data
– Verification of integrity of packet
– Signals necessary re-transmission is required
– Keeps track of which packet has been sent and received
– Indicates receipt of packet in good or bad form
– Allows for the sending of multiple yet-to-be-acknowledged packets
Transport Layer – TCP
‹#›
B
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
Empty
.
.
.
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
UDP (User Datagram Protocol)
– has no connection establishment
No connection state at servers
less packet overhead than TCP
light error-checking (checksum)
server doesn’t use the listen() function
server doesn’t use the accept() function
See Lecture-6-Socket Programming-Part2
UDP Basics
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
Empty
.
.
.
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Rserver 1235 0 0
Rclient 127.0.0.1 1235 0 0
You should run the server first, before running the client. You can test your client and server using the same machine by using the example run above.
Sample run:
Bits can get corrupted flag
Packets can get lost flag
Port: 1235
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
Empty
.
.
.
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Rserver 1235 0 0
Rclient 127.0.0.1 1235 0 0
The client is the sender, while the server is the receiver.
The filenames used for sending and saving have been fixed in the start-up codes (i.e. data_for_transmission.txt, data_received.txt).
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
Empty
.
.
.
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Rserver 1235 0 0
Rclient 127.0.0.1 1235 0 0
The client sends the contents of the file line by line. One packet contains exactly one line. In order to implement reliable data transfer, you will have to modify the packet header to add more details.
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
Empty
.
.
.
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Rserver 1235 0 0
Rclient 127.0.0.1 1235 0 0
The objective is for you to implement a reliable data transfer protocol. You can choose to implement a simple stop-and-wait protocol or any of the pipe-lining protocols (i.e. Go Back-N, Selective Repeat).
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Receives file contents
line-by-line, then stores everything
into a file
Reads file, then sends the contents
1 line at a time
UNRELIABLE CHANNEL
NETWORK LAYER
TRANSPORT LAYER
APPLICATION LAYER
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Receives file contents
line-by-line, then stores everything
into a file
Reads file, then sends the contents
1 line at a time
UNRELIABLE CHANNEL
NETWORK LAYER
TRANSPORT LAYER
APPLICATION LAYER
Simulated by a function named send_unreliably()
10
Unreliable Channel Simulation
int send_unreliably( int s, char * send_buffer,
struct sockaddr* remoteaddress) {
int fate=packets_fate(); //random number generator: 0, 1, 2
if (fate==0){ //no problem will be introduced
bytes = sendto(s, send_buffer, …)
printf(“<-- SEND: %s \n",send_buffer);
} else if (fate== 1){ // introduce corrupted bits
send_buffer[damage_bit()]=random_char();
send_buffer[damage_bit()]=random_char();
bytes = sendto(s, send_buffer, ...)
printf("<-- DAMAGED %s \n",send_buffer);
…
} else if(fate==2){ // lose the packet
printf("X-- LOST %s \n",send_buffer);
}
}
You are not allowed to modify this function in the assignment.
UDP segment structure
Optional in IPv4
int sendto(
SOCKET s,
char *buf,
int msglen,
int flags,
struct sockaddr *to,
int tolen
);
Size of data may vary
Header + data, in bytes
Send data through a socket:
sendto(SOCKET s, char *msg, int msglen, int flags,
struct sockaddr *to, int tolen);
sendto()
Examples:
bytes = sendto(s, send_buffer, strlen(send_buffer),0,(result->ai_addr),sizeof(struct sockaddr) ); //IPv4
int sin6len = sizeof(struct sockaddr_in6); //IPv6
bytes = sendto(s, send_buffer, strlen(send_buffer), 0, (struct sockaddr *)&clientAddress, sin6len);
s = socket (inside the socket descriptor: port and IP address…)
msg = a pointer to a buffer (array of characters)
msglen = the length of the buffer
flags = 0 (forget about them for this exercise…)
to=structure of address with the IP / port #
tolen=length of the structure
PARAMETERS
The WSAStartup function is called to initiate use of WS2_32.dll.
Every Winsock application must load the appropriate version of the Winsock DLL. If you fail to load the Winsock library before calling a Winsock function, the function will return a SOCKET_ERROR and the error will be WSANOTINITIALISED .
Loading the Winsock library is accomplished by calling the WSAStartup function
WSVERS
The high order byte specifies the minor version (revision) number; the low-order byte specifies the major version number.
Receive data
int recvfrom(SOCKET s, char *msg, int msglen,
int flags, struct sockaddr *from, int *fromlen)
recvfrom()
Example:
recvfrom(s, rbuffer, 1, 0,(struct sockaddr*) &from, &len); //IPv4
int sin6len = sizeof(struct sockaddr_in6); //IPv6
bytes = recvfrom(s, receive_buffer, sizeof(receive_buffer), 0,
(struct sockaddr*)&serverAddress,&sin6len ); //IPv6
s = socket (inside the socket descriptor: port and IP address…)
msg = a pointer to a buffer
msglen = the length of the buffer
flags = 0
from =structure of address with the IP / port #
fromlen=length of the structure
PARAMETERS
‹#›
The WSAStartup function is called to initiate use of WS2_32.dll.
Every Winsock application must load the appropriate version of the Winsock DLL. If you fail to load the Winsock library before calling a Winsock function, the function will return a SOCKET_ERROR and the error will be WSANOTINITIALISED .
Loading the Winsock library is accomplished by calling the WSAStartup function
WSVERS
The high order byte specifies the minor version (revision) number; the low-order byte specifies the major version number.
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Receives file contents
line-by-line, then stores into a file
Destination Port: 1235
DATA
checksum
Length of segment
Reads file, then sends the contents
1 line at a time
UDP SEGMENT
Client – Server
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_for_transmission.txt
SERVER
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Receives file contents
line-by-line, then stores into a file
Destination Port: 1235
DATA
0 ABCDEF
checksum
Length of segment
Reads file, then sends the contents
1 line at a time
PACKET 0
‘\r’
‘\n’
CRC_NUM
User-defined
Start-up Codes
(Client-Server)
Let’s have a look at the CRC function provided as part of the start-up codes and the CRC test program.
CRC
//*******************************************************************
// CREATE CLIENT’S SOCKET
//*******************************************************************
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
printf("socket failed\n");
WSACleanup();
exit(1);
}
//nonblocking option
u_long iMode=1;
ioctlsocket(s, FIONBIO, &iMode);
Socket (in non-blocking mode)
We need to set our socket in non-blocking mode of operation.
This prevents the recvfrom() function from stopping and waiting for a packet.
Remember, packets could be lost in our simulation of the unreliable channel.
Done in the client-side only.
Set the socket I/O mode: In this case FIONBIO
enables or disables the blocking mode for the
socket based on the numerical value of iMode.
If iMode = 0, blocking is enabled;
If iMode != 0, non-blocking mode is enabled.
Start-up Codes (Client – Server)
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
data_for_transmission.txt
SERVER
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Receives file contents
line-by-line, then stores into a file
Reads file using fgets(), then sends the
contents 1 line at a time
Loop:
send_unreliably(data)
Sleep(1)
recvfrom()
Loop:
recvfrom()
send_unreliably(ACK)
fopen(“data_for_transmission.txt”, rb)
fopen(“data_received.txt”, w)
Non-blocking mode
Start-up Codes (Client – Server)
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
data_for_transmission.txt
SERVER
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Loop:
send_unreliably(data)
recvfrom()
Loop:
recvfrom()
send_unreliably(ACK)
fopen(“data_for_transmission.txt”, rb)
fopen(“data_received.txt”, w)
Some notes on fopen() :
In text mode, carriage return–linefeed combinations are translated into single linefeeds on input (reading a file), and linefeed characters are translated to carriage return–linefeed combinations on output (writing a file).
The function void save_line_without_header(char * receive_buffer,FILE *fout) takes advantage of this knowledge.
Reading the file contents
The client reads the file contents line by line using fgets()
fgets(send_buffer, SEGMENT_SIZE, fin)
stops reading the file when SEGMENT_SIZE-1 characters have been read, or either it encounters a newline or EOF, whichever happens first :
a new line character (‘\n’)(copied into send_buffer)
EOF (End-Of-File) character
a NULL-termination character (‘\0’) is automatically appended
this is counted as one of the characters
strlen() – counts the number of characters excluding the NULL-character
CLIENT
A
B
C
‘\n’
‘\0’
send_buffer
strlen()=4
‘\0’
‘\0’
send_buffer
strlen()-1
0
1
2
3
4
0
1
2
3
4
A
B
C
Data Format
CLIENT
A
B
C
‘\n’
‘\0’
send_buffer
strlen()=4
‘\0’
‘\0’
send_buffer
strlen()-1
0
1
2
3
4
0
1
2
3
4
A
B
C
Destination Port: 1235
DATA
ABC
checksum
Length of segment
PACKET 0
‘\r’
‘\n’
CRC_NUM
User-defined
Remove the line feed character from the row of data read from the file
UDP datagram
CLIENT
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
data_for_transmission.txt
SERVER
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
data_received.txt
Rclient_UDP.cpp
Rserver_UDP.cpp
socket
socket
Loop:
send_unreliably(data)
recvfrom()
Loop:
recvfrom()
send_unreliably(ACK)
fopen(“data_for_transmission.txt”, rb)
fopen(“data_received.txt”, w)
send_unreliably(”CLOSE”)
closesocket()
Write everything into data_received.txt
fclose()
closesocket()
Start-up Codes (Client – Server)
Non-blocking mode
Let’s see more details...
Start-up Codes (Client – Server)
CLIENT
SERVER
Loop:
read one line from file
if(not EOF){
create packet with header fields
store packet into send_buffer
send_unreliably(send_buffer)
Sleep(1);
recvfrom(receive_buffer)
trim ‘\r’, ‘\n’ from receive_buffer
} else {
fclose()
send_unreliably(”CLOSE”)
}
Loop:
recvfrom(receive_buffer)
trim ‘\r’, ‘\n’ from receive_buffer
process receive_buffer
if(receive_buffer contains DATA){
create ACK packet
send_unreliably(ACK)
save_line_without_header()
} else {
fclose()
}
fopen(“data_for_transmission.txt”, rb)
fopen(“data_received.txt”, w)
closesocket()
closesocket()
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
Should be modified according to the length of your packet header
Let’s have a look at the Start-up Codes (downloadable from Stream)
Start-up Codes
Recommended Way of Testing the Codes
(Client-Server)
Parameters Settings
Parameters (Client – Server)
CLIENT
SERVER
Rclient_UDP.cpp
Rserver_UDP.cpp
Rserver 1235 0 0
Rclient 127.0.0.1 1235 0 0
Sample run:
Bits can be corrupted
Packets can be lost
CLIENT SERVER COMMENTS
00 00 Packets can never be corrupted nor lost
01 00 Client may lose packets
00 01 Server may lose ACK packets
01 01 Both client and server may lose packets
10 00 Client may send packets with corrupted bits
00 10 Server may send ACKs with corrupted bits
10 10 Packets from both client and server may have corrupted bits
11 11 Packets from both client and server may have corrupted bits; packets may be lost as well
Ultimate Test
CLIENT
SERVER
Rclient_UDP.cpp
Rserver_UDP.cpp
Rserver 1235 1 1
Rclient 127.0.0.1 1235 1 1
Ultimate Test:
Bits can be corrupted
Packets can be lost
You can simply inspect the contents of data_for_transmission.txt and data_received.txt, to check to see if they are exactly the same.
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
data_for_transmission.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
data_received.txt
Testing using a batch file
Run.bat
START cmd /k "RServer_UDP_ipv6\Rserver_UDP 1235 1 0"
START cmd /k "RClient_UDP_ipv6\Rclient_UDP localhost 1235 1 0"
Adding data transfer reliability
Extending the codes
Let’s have a look at the Go-Back N Protocol Specifications…
See Lecture-7-Transport Layer-Part-1 (Slide #37)
Go-Back N
Pipelining Protocol (Go Back-N)
CLIENT (sender)
base
base + (N-1)
ABC
PACKET 0
‘\r’
‘\n’
CRC_NUM
ABC
PACKET 1
‘\r’
‘\n’
CRC_NUM
ABC
PACKET 2
‘\r’
‘\n’
CRC_NUM
Send a Window’s worth of packets
N=Window size = 4
Sequence Number Space
Pipelining Protocol (Go Back-N)
base
base + (N-1)
ABC
PACKET 0
‘\r’
‘\n’
CRC_NUM
ABC
PACKET 1
‘\r’
‘\n’
CRC_NUM
ABC
PACKET 2
‘\r’
‘\n’
CRC_NUM
Send a Window’s worth of packets
N = Window size = 4
nextSequenceNum-1
Packets sent but not yet ACKed
...
nextSequenceNum
CLIENT (sender)
Pipelining Protocol (Go Back-N)
base
base + (N-1)
N = Window size = 4
nextSequenceNum-1
Packets sent but not yet ACKed
nextSequenceNum
base
baseMax
ACKnum
We need to keep track of the ACK number received
CLIENT (sender)
Pipelining Protocol (Go Back-N)
N = Window size = 4
Upon receipt of an ACK, slide the window forward
base=0
baseMax=3
ACKnum=1
base=ACKnum+1
baseMax=base+(N-1)
0
1
2
3
0
1
2
3
4
5
time=0
time=1
CLIENT (sender)
Pipelining Protocol (Go Back-N)
N = Window size = 4
Transmit more packets (up to baseMax)
base=0
baseMax=3
ACKnum=1
base=ACKnum+1
baseMax=base+(N-1)
0
1
2
3
0
1
2
3
4
5
time=0
time=2
CLIENT (sender)
Extending the codes
WARNING: The following pseudo codes are not complete. They are meant just to give you an idea of how to implement a sliding Window protocol.
The statements highlighted in red corresponds to the suggested routines that need to be incorporated.
40
Calculating the Elapsed Time
clock()
void wait ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
clock_t startTime, elapsedTime;
startTime = clock();
…
...
elapsedTime = (clock() - startTime) / CLOCKS_PER_SEC;
40
Extending the codes
Loop:
read one line from file
if(not EOF){
create packet with header fields
store packet into send_buffer
send_unreliably(send_buffer)
Sleep(1);
recvfrom(receive_buffer)
trim ‘\r’, ‘\n’ from receive_buffer
extract ACK number
update base, baseMax
} else {
fclose()
send_unreliably(”CLOSE”)
}
Loop:
recvfrom(receive_buffer)
trim ‘\r’, ‘\n’ from receive_buffer
extract CRC1 from receive_buffer
extract data from receive_buffer
calc CRC2 using data
if(CRC1 == CRC2){
extract Packet Num
if(PacketNum is in-order){
if(receive_buffer contains DATA){
create ACK packet
send_unreliably(ACK)
save_line_without_header
update expectedSeqNum, base
}
else if(receive_buffer contains CLOSE) {
fclose(); closesocket();
}
}
}
fopen(“data_for_transmission.txt”, r)
fopen(“file1_Saved”, w)
closesocket()
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
…
SERVER
CLIENT
Other Helpful Functions
See tokenizer2.cpp
strtok()
Other Helpful Functions
strchr
const char * strchr ( const char * str, int character ); char * strchr ( char * str, int character );
Locate first occurrence of character in string
Returns a pointer to the first occurrence of character in the C string str.
The terminating null-character is considered part of the C string. Therefore, it can also be located to retrieve a pointer to the end of a string.
/docProps/thumbnail.jpeg