Implementing a Reliable Data Transfer Protocol

advertisement
Reliable Data Transfer Protocol
IMPLEMENTATION TIPS
Recall
socket
door
application
writes data
application
reads data
TCP
send buffer
TCP
receive buffer
socket
door
Packet ->
 Reliable Data Transfer Mechanisms:
 Checksum
 Timer
- Verification of integrity of packet
- Signals necessary re-transmission is required
 Sequence
number
- Keeps track of which packet has been sent and received
 ACK
- Indicates receipt of packet in good or bad form
 NAK
 Window,
pipelining
- Allows for the sending of multiple yet-to-be-acknowledged
packets
Transport Layer
– TCP
2
B
Client - Server
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
Empty
.
.
.
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
socket
UDP Basics
• See Lecture-2012-6-Socket Programming-Part2
(Slide #4)
Client - Server
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
Empty
.
.
.
socket
socket
Port: 1235
Sample run:
Rclient 127.0.0.1 1235 0 0
Bits can be corrupted
Rserver 1235 0 0
Packets can be lost
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.
Client - Server
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
Empty
.
.
.
socket
Rclient 127.0.0.1 1235 0 0
socket
Rserver 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. File1_Windows.txt, File1_Saved.txt).
Client - Server
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
Empty
.
.
.
socket
Rclient 127.0.0.1 1235 0 0
socket
Rserver 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
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
Empty
.
.
.
socket
Rclient 127.0.0.1 1235 0 0
socket
Rserver 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
Rclient_UDP.cpp
CLIENT
Rserver_UDP.cpp
APPLICATION LAYER
File1_Windows.txt
SERVER
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
socket
socket
Reads file, then sends the contents
1 line at a time
Receives file contents
line-by-line, then stores everything
into a file
TRANSPORT LAYER
UNRELIABLE CHANNEL
NETWORK LAYER
Client - Server
Rclient_UDP.cpp
CLIENT
Rserver_UDP.cpp
APPLICATION LAYER
File1_Windows.txt
SERVER
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
socket
socket
Reads file, then sends the contents
1 line at a time
Receives file contents
line-by-line, then stores everything
into a file
TRANSPORT LAYER
Simulated by a
function named
send_unreliably()
UNRELIABLE CHANNEL
NETWORK LAYER
Unreliable Channel Simulation
int send_unreliably( int s, char * send_buffer,
struct sockaddr_in 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);
…
You are not allowed to modify
} else if(fate==2){ // lose the packet
this function in the
printf("X-- LOST %s \n",send_buffer);
assignment.
}
}
UDP segment structure
Optional in IPv4
• The optional parameters are not even included in
the sendto() function.
int sendto(
SOCKET s,
char *buf,
int msglen,
int flags,
struct sockaddr *to,
int tolen
• The O/S will automatically
provide the IP address of
the sender of the
segment.
);
sendto()
•Send data through a socket:
sendto(SOCKET s, char *msg, int msglen, int flags,
struct sockaddr *to, int *tolen);
PARAMETERS
s = socket (inside the socket descriptor: port and IP address...)
msg = a pointer to a buffer (could be a string)
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
Example:
sendto(s, sbuffer, strlen(sbuffer),0,(struct sockaddr*) to, &len);
recvfrom()
 Receive data
int recvfrom(SOCKET s, char *msg, int msglen,
int flags, struct sockaddr *from, int *fromlen)
PARAMETERS
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
Example:
recvfrom(s, rbuffer, 1, 0,(struct sockaddr *) &from, &len);
14
Client - Server
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
socket
socket
Reads file, then sends the contents
1 line at a time
Receives file contents
line-by-line, then stores into a file
UDP SEGMENT
Destination Port: 1235 checksum Length of segment DATA
Client - Server
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
socket
Reads file, then sends the contents
1 line at a time
socket
Receives file contents
line-by-line, then stores into a file
Destination Port: 1235 checksum Length of segment DATA
CRC_NUM PACKET 0 0 ABCDEF ‘\r’ ‘\n’
User-defined
CRC
Let’s have a look at the CRC function
provided as part of the start-up codes
and the CRC test program.
Socket (in non-blocking mode)
//*******************************************************************
// 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);
• 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.
Start-up Codes (Client – Server)
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
socket
Reads file using fgets(), then sends the
contents 1 line at a time
fopen(“file1_Windows.txt”, r)
Loop:
send_unreliably(data)
recvfrom()
socket
Receives file contents
line-by-line, then stores into a file
fopen(“file1_Saved”, w)
Loop:
recvfrom()
send_unreliably(ACK)
Reading the file contents
The client reads the file contents line by line using fgets()
CLIENT
fgets(send_buffer, SEGMENT_SIZE, fin)
• stops reading the file when it encounters either:
• a new line character (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
strlen()=4
A
0
A
0
B
1
B
1
C
2
C
2
‘\n’
3
4
‘\0’
3
4
‘\0’
send_buffer
strlen()-1
‘\0’
send_buffer
Data Format
CLIENT
Destination Port: 1235 checksum Length of segment DATA
CRC_NUM PACKET 0 ABC ‘\r’ ‘\n’
User-defined
Remove the line feed character from the row of data read from the file
strlen()=4
A
0
A
0
B
1
B
1
C
2
C
2
‘\n’
3
4
‘\0’
3
4
‘\0’
send_buffer
strlen()-1
‘\0’
send_buffer
Start-up Codes (Client – Server)
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
File1_Windows.txt
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
socket
fopen(“file1_Windows.txt”, r)
Loop:
send_unreliably(data)
recvfrom()
send_unreliably(”CLOSE”)
closesocket()
socket
fopen(“file1_Saved”, w)
Loop:
recvfrom()
send_unreliably(ACK)
Write everything into file1_Saved.txt
fclose()
closesocket()
Start-up Codes (Client – Server)
CLIENT
fopen(“file1_Windows.txt”, r)
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
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”)
}
closesocket()
SERVER
fopen(“file1_Saved”, w)
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
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()
}
closesocket()
Start-up Codes
Let’s have a look at the Start-up Codes
(downloadable from our website)
Parameters Settings
Parameters (Client – Server)
Rclient_UDP.cpp
Bits can be corrupted
Rserver_UDP.cpp
CLIENT
SERVER
Packets can be lost
Sample run:
Rclient 127.0.0.1 1235 0 0
Rserver 1235 0 0
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 have corrupt bits
00
10
Server may have corrupt bits
10
10
Both client and server may have corrupted bits
11
11
Both client and server may have corrupted bits and may
lose packets
Ultimate Test
Rclient_UDP.cpp
Rserver_UDP.cpp
CLIENT
SERVER
Bits can be corrupted
Ultimate Test:
Packets can be lost
Rclient 127.0.0.1 1235 1 1
Rserver 1235 1 1
You can simply inspect the contents of File1_Windows.txt and
File1_Saved.txt, to check to see if they are exactly the same.
File1_Windows.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
File1_Saved.txt
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
Extending the codes
Go-Back N
Let’s have a look at the Go-Back N Protocol
Specifications…
See Lecture-2012-7-Transport Layer-Part-1
(Slide #37)
Pipelining Protocol (Go Back-N)
CLIENT
(sender)
CRC_NUM
PACKET 0
Send a Window’s worth of packets
ABC
‘\r’
‘\n’
CRC_NUM
PACKET 1
ABC
‘\r’
‘\n’
CRC_NUM
N=Window size = 4
base
base + (N-1)
Sequence Number Space
PACKET 2
ABC
‘\r’
‘\n’
Pipelining Protocol (Go Back-N)
CLIENT
(sender)
CRC_NUM
PACKET 0
Send a Window’s worth of packets
ABC
‘\r’
‘\n’
CRC_NUM
PACKET 1
ABC
‘\r’
‘\n’
CRC_NUM
N = Window size = 4
base + (N-1)
base
nextSequenceNum
Packets sent but
not yet ACKed
nextSequenceNum-1
PACKET 2
ABC
‘\r’
‘\n’
...
Pipelining Protocol (Go Back-N)
CLIENT
(sender)
Packets sent but
not yet ACKed
N = Window size = 4
base + (N-1)
nextSequenceNum
base
nextSequenceNum-1
baseMax
base
ACKnum
We need to keep
track of the ACK
number received
Pipelining Protocol (Go Back-N)
CLIENT
(sender)
N = Window size = 4
0
1
2
3
time=0
base=0
Upon receipt of an
ACK, slide the
window forward
baseMax=3
ACKnum=1
0
1
2
3
4
5
time=1
base=ACKnum+1
baseMax=base+(N-1)
Pipelining Protocol (Go Back-N)
CLIENT
(sender)
N = Window size = 4
0
1
2
3
time=0
base=0
Transmit more packets
(up to baseMax)
baseMax=3
ACKnum=1
0
1
2
3
4
5
time=2
base=ACKnum+1
baseMax=base+(N-1)
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.
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;
38
Extending the codes
CLIENT
fopen(“file1_Windows.txt”, r)
Loop:
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
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”)
}
SERVER
fopen(“file1_Saved”, w)
Loop:
0 ABCDEF
1 ABCDEF
2 ABCDEF
3 ABCDEF
...
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();
closesocket()
}
}
}
Other Helpful Functions
strchr
• <cstring>
• 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.
Download