Java BUMP implementation.

please read the attachments in the zipped file:

Save Time On Research and Writing
Hire a Pro to Write You a 100% Plagiarism-Free Paper.
Get My Paper

The word doc is where the requirements are, the rest are the resources.

BUMP implementation in Java x

The project is to implement the BUMP client in java, with 
window size 1. Here is an 

overview of the three WUMP protocols
 (BUMP, HUMP, and CHUMP). Here are the files 

Save Time On Research and Writing
Hire a Pro to Write You a 100% Plagiarism-Free Paper.
Get My Paper

wumppkt.java
, containing the packet format classes, and 

wclient.java
, which contains an outline of the actual program. Only the latter file should be modified; you should 
not have to make changes to wumppkt.java.

What you are to do is the following, by modifying and extending the wclient.java outline file:

· Implement the basic transfer

· Add all appropriate packet sanity checks: timeouts, host/port, size, opcode, and block number

· Generate output. The transferred file is to be written to System.out. A status message about every packet (listing size and block number) is to be written to System.err. Do 
not confuse these!

· Terminate after a packet of size less than 512 is received

· Implement an appropriate “dallying” strategy

· send an ERROR packet if it receives a packet from the wrong port. The appropriate ERRCODE in this case is EBADPORT.

An outline of the program main loop is attached

recommended that you implement this in phases, as follows.

1. Latch on to the new port: save the port number from Data[1], and make sure all ACKs get sent to this port. This will mean that the transfer completes. You should also make sure the client stops when a packet with less than 512 bytes of data is received. Unless you properly record the source port for Data[1], you have no place to which to send ACK[1]!

2. For each data packet received, write the data to System.out. All status messages should go to System.err, so the two data streams are separate if 
stdout is redirected. To write to System.out, use System.out.write:
        
System.out.write(byte[] buf, int offset, int length);
For your program, offset will be 0, buf will typically be dpacket.data(), where dpacket is of type DATA (wumppkt.DATA). The length will be dpacket.size() – wumppkt.DHEADERSIZE (or, equivalently, dg.getLength() – wumppkt.DHEADERSIZE, where dg is a DatagramPacket object).

3. Add sanity checks, for (in order) host/port, packet size, opcode, and block number.

4. Handle timeouts, by retransmitting the most recently sent packet when the elapsed time exceeds a certain amount (4 seconds?). One way to do this is to keep a DatagramPacket variable LastSent, which can either be reqDG or ackDG, and just resend LastSent. Note that the response to an InterruptedIOException, a “true” timeout, will simply be to continue the loop again.

5. Add support for an dallying and error packets. After the client has received the file, dallying means to wait 2.0 – 3.0 timeout intervals (or more) to see if the final data packet is retransmitted. If it is, it means that the final ACK was lost. The dally period gives the client an opportunity to resend the final ACK. Error packets are to be sent to any sender of an apparent data packet that comes from the wrong port.

vanilla   Normal transfer

lose      Lose everything after the first windowful (min 3). It will be retransmitted when you retransmit the previous ACK.

spray    Constant barrage of data[1]. Implies LOSE too. In this case, no timeout events will occur; you 
must check for elapsed time.

delay    Delays sending packet 1, prompting a duplicate REQ and thus results in multiple server instances on multiple ports.

reorder  Sends the first windowful in the wrong order. You’re probably not implementing windows.

dupdata2

DATA[2] is sent twice

losedata2

DATA[2] is lost on initial send, until you resend ACK[1]

marspacket

A packet from the wrong port (a “martian” port) arrives

badopcode

a packet arrives with an incorrect opcode

nofile

you get an error packet with a NO FILE error code.

At this point, the only ones that work on port 4716 are 
vanilla, 
lose2 (losedata2) and 
dup2 (dupdata2).

wumppkt.java

wumppkt.java

// The following implements the packet formats for BUMP and HUMP.

// Each individual packet type derives from class BASE, containing

// protocol and opcode fields only; we don’t really use this inheritance

// hierarchy though.

// packets can be constructed with the applicable constructors;

// each ctor requires parameters for the necessary fields.

// when possible, there is a “convenience” ctor setting proto = BUMPPROTO.

// The “raw” packet format, as sent and received via DatagramSocket,

// is byte[].  Packets (at least those that one might *receive*)

// can be constructed from a byte[]. For DATA packets, we also need

// to specify the length of the packet, not necessarily the same as

// the length of the byte[] buffer.

// All packet classes also have a write() member function that

// writes out the packet fields into a byte[], for sending.

//import java.lang.*;     //pld

//import java.net.*;      //pld

//import java.lang.System.*;

import
 java
.
io
.
*
;

public
 
class
 wumppkt 
{

    
public
 
static
 
final
 
short
 BUMPPROTO 
=
 
1
;

    
public
 
static
 
final
 
short
 HUMPPROTO 
=
 
2
;

    
public
 
static
 
final
 
short
 CHUMPPROTO
=
 
3
;

    
public
 
static
 
final
 
short
 
REQop
 
=
 
1
;

    
public
 
static
 
final
 
short
 
DATAop
=
 
2
;

    
public
 
static
 
final
 
short
 
ACKop
 
=
 
3
;

    
public
 
static
 
final
 
short
 
ERRORop
=
4
;

    
public
 
static
 
final
 
short
 
HANDOFFop
=
5
;

    
public
 
static
 
final
 
short
 SERVERPORT 
=
 
4715
;

    
public
 
static
 
final
 
short
 SAMEPORT   
=
 
4716
;

    
public
 
static
 
final
 
int
   INITTIMEOUT 
=
 
3000
;
   
// milliseconds

    
public
 
static
 
final
 
int
   SHORTSIZE 
=
 
2
;
            
// in bytes

    
public
 
static
 
final
 
int
   INTSIZE   
=
 
4
;

    
public
 
static
 
final
 
int
   BASESIZE  
=
 
2
;

    
public
 
static
 
final
 
int
   MAXDATASIZE
=
512
;

    
public
 
static
 
final
 
int
   DHEADERSIZE 
=
 BASESIZE 
+
 SHORTSIZE 
+
 INTSIZE
;
 
// DATA header size

    
public
 
static
 
final
 
int
   MAXSIZE  
=
 DHEADERSIZE 
+
 MAXDATASIZE
;

    
public
 
static
 
final
 
int
   EBADPORT  
=
1
;
  
/* packet from wrong port */

    
public
 
static
 
final
 
int
   EBADPROTO 
=
2
;
  
/* unknown protocol */

    
public
 
static
 
final
 
int
   EBADOPCODE
=
3
;
  
/* unknown opcode */

    
public
 
static
 
final
 
int
   ENOFILE   
=
4
;
  
/* REQ for nonexistent file */

    
public
 
static
 
final
 
int
   ENOPERM   
=
5
;
  
/* REQ for file with wrong permissions */

static
 
int
 proto
(
byte
[]
 buf
)
 
{

    
return
  buf
[
0
];

}

static
 
int
 opcode
(
byte
[]
 buf
)
 
{

    
return
 buf
[
1
];

}

    
public
 
static
 
void
 w_assert
(
boolean
 cond
,
 
String
 s
)
 
{

        
if
 
(
cond
)
 
return
;

        
System
.
err
.
println
(
“assertion failed: ”
 
+
 s
);

        java
.
lang
.
System
.
exit
(
1
);

    
}

//************************************************************************

public
 
class
 BASE 
{
 
//implements Externalizable {

// don’t construct these unless the buffer has length >=4!

// the data:

    
private
 
byte
  _proto
;

    
private
 
byte
  _opcode
;

    
//———————————

    
public
 BASE
(
int
 proto
,
 
int
 opcode
)
 
{

        
//super();              // call to base ctor

        _proto 
=
 
(
byte
)
 proto
;

        _opcode 
=
 
(
byte
)
 opcode
;

    
}

    
public
 BASE
(
byte
[]
 buf
)
 
{
        
// constructs pkt out of packetbuf

    
}

    
public
 BASE
()
 
{}
                 
// packet ctors do all the work!

    
public
 
byte
[]
 write
()
 
{
         
// not used

        
return
 
null
;

    
}

    
public
 
int
 size
()
 
{

        
return
 BASESIZE
;

    
}

    
public
 
int
 proto
()
 
{
return
 _proto
;}

    
public
 
int
 opcode
()
 
{
return
 _opcode
;}

}

//*******************

public
 
class
 REQ 
extends
 BASE 
{

    
private
 
short
  _winsize
;

    
private
 
String
 _filename
;

    
//———————————

    
public
 REQ
(
int
 proto
,
 
int
 winsize
,
 
String
 filename
)
 
{

        
super
(
proto
,
 
REQop
);

        _winsize 
=
 
(
short
)
 winsize
;

        _filename 
=
 filename
;

    
}

    
public
 REQ
(
int
 winsize
,
 
String
 filename
)
 
{

        
this
(
BUMPPROTO
,
 winsize
,
 filename
);

    
}

    
public
 REQ
(
byte
[]
 buf
)
 
{
            
// not complete but not needed

        
//super(BUMPPROTO, REQop);

    
}

    
public
 
byte
[]
 write
()
 
{

        
ByteArrayOutputStream
 baos 
=
 
new
 
ByteArrayOutputStream
(
size
());

        
DataOutputStream
 dos 
=
 
new
 
DataOutputStream
(
baos
);

        
try
 
{

            
//writeExternal(dos);

            dos
.
writeByte
(
super
.
proto
());

            dos
.
writeByte
(
super
.
opcode
());

            dos
.
writeShort
(
_winsize
);

            dos
.
writeBytes
(
_filename
);

            dos
.
writeByte
(
0
);

            
return
 baos
.
toByteArray
();

            
}
 
catch
 
(
IOException
 ioe
)
 
{

                
System
.
err
.
println
(
“BASE packet output conversion failed”
);

                
return
 
null
;

            
}

        
//return null;

    
}

    
public
 
int
 size
()
 
{

        
return
 
super
.
size
()
 
+
 SHORTSIZE 
+
 _filename
.
length
()
 
+
 
1
;

    
}

    
public
 
String
 filename
()
 
{
return
 _filename
;}

}

//*******************

public
 
class
 ACK 
extends
 BASE 
{

    
private
 
int
 _blocknum
;

   
//———————————

   
public
 ACK
(
int
 blocknum
)
 
{

        
this
(
BUMPPROTO
,
 blocknum
);

    
}

    
public
 ACK
(
short
 proto
,
 
int
 blocknum
)
 
{

        
super
(
proto
,
 
ACKop
);

        _blocknum 
=
 blocknum
;

    
}

    
public
 
int
 blocknum
()
 
{
return
 _blocknum
;}

    
public
 
void
 setblock
(
int
 blocknum
)
 
{
_blocknum 
=
 blocknum
;}

    
public
 
byte
[]
 write
()
 
{

        
ByteArrayOutputStream
 baos 
=
 
new
 
ByteArrayOutputStream
(
size
());

        
DataOutputStream
 dos 
=
 
new
 
DataOutputStream
(
baos
);

        
try
 
{

            
//writeExternal(dos);

            dos
.
writeByte
(
super
.
proto
());

            dos
.
writeByte
(
super
.
opcode
());

            dos
.
writeShort
(
0
);
          
// padding

            dos
.
writeInt
(
_blocknum
);

            
return
 baos
.
toByteArray
();

            
}
 
catch
 
(
IOException
 ioe
)
 
{

                
System
.
err
.
println
(
“ACK packet output conversion failed”
);

                
return
 
null
;

            
}

     
}

    
public
 
int
 size
()
 
{

        
return
 
super
.
size
()
 
+
 SHORTSIZE 
+
 INTSIZE
;

    
}

    
public
 ACK
(
byte
[]
 buf
)
 
{}
       
// not complete but not needed

}

//*******************

public
 
class
 DATA 
extends
 BASE 
{

    
private
 
int
 _blocknum
;

    
private
 
byte
[]
 _data
;

    
//———————————

    
public
 DATA
(
int
 proto
,
 
int
 blocknum
,
 
byte
[]
 data
)
 
{

        
super
(
proto
,
 
DATAop
);

        _blocknum 
=
 blocknum
;

        _data 
=
 data
;

    
}

    
public
 DATA
(
int
 proto
,
 
int
 blocknum
,
 
byte
[]
 data
,
 
int
 len
)
 
{

        
super
(
proto
,
 
DATAop
);

        _blocknum 
=
 blocknum
;

        _data 
=
 data
;

    
}

    
public
 DATA
(
byte
[]
 buf
,
 
int
 bufsize
)
 
{

        
this
(
BUMPPROTO
,
 buf
,
 bufsize
);

    
}

    
// for building a DATA out of incoming buffer:

    
public
 DATA
(
int
 proto
,
 
byte
[]
 buf
,
 
int
 bufsize
)
 
{

        
super
(
proto
,
 
DATAop
);

        
ByteArrayInputStream
 bais 
=
 
new
 
ByteArrayInputStream
(
buf
,
 
0
,
 bufsize
);

        
DataInputStream
 dis 
=
 
new
 
DataInputStream
(
bais
);

        
try
 
{

            
int
 p 
=
 dis
.
readByte
();

            w_assert
(
p
==
proto
,
 
“Expecting proto ”
 
+
 proto 
+
 
“, got ”
 
+
 p
);

            
int
 o 
=
 dis
.
readByte
();

            w_assert
(
o
==
DATAop
,
 
“Expecting opcode=DATA, got ”
 
+
 o
);

            
int
 pad
=
dis
.
readShort
();

            _blocknum 
=
 
(
dis
.
readInt
());

            _data  
=
 
new
 
byte
[
dis
.
available
()];

            dis
.
read
(
_data
);

        
}
 
catch
 
(
IOException
 ioe
)
 
{

            
System
.
err
.
println
(
“DATA packet conversion failed”
);

            
return
;

        
}

    
}

    
public
 DATA
(
int
 proto
)
 
{
            
// for creating “empty” DATA objects

        
super
(
proto
,
 
DATAop
);

        _blocknum 
=
 
0
;

        _data 
=
 
new
 
byte
[
MAXDATASIZE
];

    
}

    
public
 DATA
()
 
{
 
this
(
BUMPPROTO
);
 
}

    
public
 
int
 blocknum
()
 
{
return
 _blocknum
;}

    
public
 
byte
[]
 data
()
 
{
return
 _data
;}

    
public
 
byte
[]
 write
()
 
{
     
// not complete but not needed

        
return
 
null
;

    
}

    
public
 
int
 size
()
 
{

        
return
 
super
.
size
()
 
+
 SHORTSIZE 
+
 INTSIZE 
+
 _data
.
length
;

    
}

}

//*******************

public
 
class
 ERROR 
extends
 BASE 
{

    
private
 
short
 _errcode
;

    
//———————————

    
public
 ERROR
(
short
 proto
,
 
short
 errcode
)
 
{

        
super
(
proto
,
 
ERRORop
);

        _errcode 
=
 errcode
;

    
}

    
public
 
short
 errcode
()
 
{
return
 _errcode
;}

    
public
 
byte
[]
 write
()
 
{

        
ByteArrayOutputStream
 baos 
=
 
new
 
ByteArrayOutputStream
(
size
());

        
DataOutputStream
 dos 
=
 
new
 
DataOutputStream
(
baos
);

        
try
 
{

            
//writeExternal(dos);

            dos
.
writeByte
(
super
.
proto
());

            dos
.
writeByte
(
super
.
opcode
());

            dos
.
writeShort
(
_errcode
);

            
return
 baos
.
toByteArray
();

        
}
 
catch
 
(
IOException
 ioe
)
 
{

            
System
.
err
.
println
(
“ERROR packet output conversion failed”
);

            
return
 
null
;

        
}

    
}

    
public
 ERROR
(
byte
[]
 buf
)
 
{
this
(
BUMPPROTO
,
 buf
);}

    
public
 ERROR
(
int
 proto
,
 
byte
[]
 buf
)
 
{

        
super
(
proto
,
 
DATAop
);

        
int
 opcode 
=
 wumppkt
.
this
.
opcode
(
buf
);

        w_assert
(
opcode 
==
 
ERRORop
,
 
“Expecting opcode=ERROR, got ”
 
+
 opcode
);

        w_assert
(
proto 
==
 wumppkt
.
this
.
proto
(
buf
),
 
“Expecting proto=”
+
proto
);

        w_assert
(
buf
.
length 
>=
 BASESIZE 
+
 SHORTSIZE
,
 
“bad ERROR pkt size of ”
 
+
 buf
.
length
);

        
ByteArrayInputStream
 bais 
=
 
new
 
ByteArrayInputStream
(
buf
,
 
0
,
 buf
.
length
);

        
DataInputStream
 dis 
=
 
new
 
DataInputStream
(
bais
);

        
try
 
{

            
int
 p 
=
 dis
.
readByte
();

            
int
 o 
=
 dis
.
readByte
();

            _errcode 
=
 dis
.
readShort
();

        
}
 
catch
 
(
IOException
 ioe
)
 
{

            
System
.
err
.
println
(
“ERROR packet conversion failed”
);

            
return
;

        
}

    
};

    
public
 
int
 size
()
 
{
return
 
super
.
size
()
 
+
 SHORTSIZE
;}

}

}

wclient.java

wclient.java

/*

    WUMP (specifically BUMP) in java. starter file

 */

import
 java
.
lang
.
*
;
     
//pld

import
 java
.
net
.
*
;
      
//pld

import
 java
.
io
.
*
;

//import wumppkt;         // be sure wumppkt.java is in your current directory

//import java.io.Externalizable;

public
 
class
 wclient 
{

    
static
 wumppkt wp 
=
 
new
 wumppkt
();
    
// stupid inner-class nonsense

    
//============================================================

    
//============================================================

    
static
 
public
 
void
 main
(
String
 args
[])
 
{

        
int
 destport 
=
 wumppkt
.
SERVERPORT
;

    destport 
=
 wumppkt
.
SAMEPORT
;
        
// 4716; server responds from same port

        
String
 filename 
=
 
“vanilla”
;

        
String
 desthost 
=
 
“ulam2.cs.luc.edu”
;

        
int
 winsize 
=
 
1
;

        
if
 
(
args
.
length 
>
 
0
)
 filename 
=
 args
[
0
];

        
if
 
(
args
.
length 
>
 
1
)
 winsize 
=
 
Integer
.
parseInt
(
args
[
1
]);

        
if
 
(
args
.
length 
>
 
2
)
 desthost 
=
 args
[
2
];

        
DatagramSocket
 s
;

        
try
 
{

            s 
=
 
new
 
DatagramSocket
();

        
}

        
catch
 
(
SocketException
 se
)
 
{

            
System
.
err
.
println
(
“no socket available”
);

            
return
;

        
}

        
try
 
{

            s
.
setSoTimeout
(
wumppkt
.
INITTIMEOUT
);
       
// time in milliseconds

        
}
 
catch
 
(
SocketException
 se
)
 
{

            
System
.
err
.
println
(
“socket exception: timeout not set!”
);

        
}

       
if
 
(
args
.
length 
!=
 
2
)
 
{

            
System
.
err
.
println
(
“usage: wclient filename  [winsize [hostname]]”
);

            
//exit(1);

        
}

        
// DNS lookup

        
InetAddress
 dest
;

        
System
.
err
.
print
(
“Looking up address of ”
 
+
 desthost 
+
 
“…”
);

        
try
 
{

            dest 
=
 
InetAddress
.
getByName
(
desthost
);

        
}

        
catch
 
(
UnknownHostException
 uhe
)
 
{

            
System
.
err
.
println
(
“unknown host: ”
 
+
 desthost
);

            
return
;

        
}

        
System
.
err
.
println
(
” got it!”
);

        
// build REQ & send it

        wumppkt
.
REQ req 
=
 wp
.
new
 REQ
(
wumppkt
.
BUMPPROTO
,
 winsize
,
 filename
);
 
// ctor for REQ

        
System
.
err
.
println
(
“req size = ”
 
+
 req
.
size
()
 
+
 
“, filename=”
 
+
 req
.
filename
());

        
DatagramPacket
 reqDG

            
=
 
new
 
DatagramPacket
(
req
.
write
(),
 req
.
size
(),
 dest
,
 destport
);

        
try
 
{
s
.
send
(
reqDG
);}

        
catch
 
(
IOException
 ioe
)
 
{

            
System
.
err
.
println
(
“send() failed”
);

            
return
;

        
}

        
//============================================================

        
// now receive the response

        
DatagramPacket
 replyDG            
// we don’t set the address here!

            
=
 
new
 
DatagramPacket
(
new
 
byte
[
wumppkt
.
MAXSIZE
]
 
,
 wumppkt
.
MAXSIZE
);

        
DatagramPacket
 ackDG 
=
 
new
 
DatagramPacket
(
new
 
byte
[
0
],
 
0
);

        ackDG
.
setAddress
(
dest
);

    ackDG
.
setPort
(
destport
);
        
// this is wrong for wumppkt.SERVERPORT version

        
int
 expected_block 
=
 
1
;

        
long
 starttime 
=
 
System
.
currentTimeMillis
();

        
long
 sendtime 
=
 starttime
;

        wumppkt
.
DATA data 
=
 wp
.
new
 DATA
();

        wumppkt
.
ACK  ack  
=
 wp
.
new
 ACK
(
0
);

        
int
 proto
;
        
// for proto of incoming packets

        
int
 opcode
;

        
int
 length
;

        
//============================================================

        
while
 
(
true
)
 
{

            
// get packet

            
try
 
{

                s
.
receive
(
replyDG
);

            
}

            
catch
 
(
SocketTimeoutException
 ste
)
 
{

                
System
.
err
.
println
(
“hard timeout”
);

                
// what do you do here??

                
continue
;

            
}

            
catch
 
(
IOException
 ioe
)
 
{

                
System
.
err
.
println
(
“receive() failed”
);

                
return
;

            
}

            
byte
[]
 replybuf 
=
 replyDG
.
getData
();

            proto 
=
 wumppkt
.
proto
(
replybuf
);

            opcode 
=
 wumppkt
.
opcode
(
replybuf
);

            length 
=
 replyDG
.
getLength
();

            
/* The new packet might not actually be a DATA packet.

             * But we can still build one and see, provided:

             *   1. proto =   wumppkt.BUMPPROTO

             *   2. opcode =  wumppkt.DATAop

             *   3. length >= wumppkt.DHEADERSIZE

             */

            
if
 
(
  proto 
==
 wumppkt
.
BUMPPROTO

                  
&&
 opcode 
==
 wumppkt
.
DATAop

                  
&&
 length 
>=
 wumppkt
.
DHEADERSIZE
)

            
{

                    data 
=
 wp
.
new
 DATA
(
replyDG
.
getData
(),
 length
);

            
}
 
else
 
{

                    data 
=
 
null
;

            
}

            
// the following seven items we can print always

            
System
.
err
.
print
(
“rec’d packet: len=”
 
+
 length
);

            
System
.
err
.
print
(
“; proto=”
 
+
 proto
);

            
System
.
err
.
print
(
“; opcode=”
 
+
 opcode
);

            
System
.
err
.
print
(
“; src=(”
 
+
 replyDG
.
getAddress
().
getHostAddress
()

                        
+
 
“/”
 
+
 replyDG
.
getPort
()
+
 
“)”
);

            
System
.
err
.
print
(
“; time=”
 
+
 
(
System
.
currentTimeMillis
()

starttime
));

            
System
.
err
.
println
();

            
if
 
(
data
==
null
)

                
System
.
err
.
println
(
”         packet does not seem to be a data packet”
);

            
else
 
{

                
System
.
err
.
println
(
”         DATA packet blocknum = ”
 
+
 data
.
blocknum
());

        
System
.
out
.
write
(
data
.
data
(),
 
0
,
 data
.
size
()
 

 wumppkt
.
DHEADERSIZE
);

        
}

            
// The following is for you to do:

            
// check port, packet size, type, block, etc

            
// latch on to port, if block == 1

            
// send ack

            ack 
=
 wp
.
new
 ACK
(
wumppkt
.
BUMPPROTO
,
 expected_block
);

            ackDG
.
setData
(
ack
.
write
());

            ackDG
.
setLength
(
ack
.
size
());

            
try
 
{
s
.
send
(
ackDG
);}

            
catch
 
(
IOException
 ioe
)
 
{

                
System
.
err
.
println
(
“send() failed”
);

                
return
;

            
}

            sendtime 
=
 
System
.
currentTimeMillis
();

        
// if it passes all the checks:

            
//write data, increment expected_block

        
// exit if data size is < 512          }   // while      } } wump_client_outline.html Outline of the wump client program main loop. There are three states: UNLATCHED, until we get a good DATA[1] from the new port LATCHED, once we've latched on to the new port DALLY, after we've received the final data packet Here's a first pass at a pseudocode outline of the main body of the program, as presented on June 6; while it is pseudocode, note that while(true) and continue are legitimate java. Note how the use of continue makes elses unnecessary. There are three main problems here: dally() is unspecified, the transition from UNLATCHED to LATCHED is unclear (and the program does not implement it correctly, clear or not), and the timeout-event handling is, well, incomplete. On June 6 we did discuss the transition to LATCHED. while (true) {         replyDG = s.receive()    // possibly a timeout         if TIMEOUT:                 retransmit previous packet (ACK or REQ)                 continue         wrong IP addr:                 continue         wrong port:            // really separate from wrong IP-addr                 send error packet                 continue         wrong length:    // can't even check for DATA opcode if there aren't enough bytes!                 continue         not DATA                 continue         create DATA packet out of replyDG         wrong blocknum:                 continue         // now we have a good packet!                 write data                 expected_block ++;                 send ACK to destport                 if (size < 512) {                         dally();            // to be discussed                         break;            // done                 } } The first fix is to clarify when we become LATCHED. This occurs when we recognize a valid DATA[1]; at that time we set expected_block >1 so
we can use this fact (expected_block > 1) as our “flag”. However, we
should check for LATCHED early in the game, and we don’t find out about
valid DATA[1] until late in the loop above. Additions are in green; in most cases we will become LATCHED during the first run through the main while loop.

while (true) {
        replyDG = s.receive()    // possibly a timeout
        if TIMEOUT:
                retransmit previous packet (ACK or REQ)
                continue
        wrong IP addr:
                continue
        wrong port:   
        // really separate from wrong
IP-addr
                only check port if expected_block == 1
                send error packet
                continue
        wrong length:   
// can’t even check for DATA opcode if there aren’t enough bytes!
                continue
        not DATA
                continue
        create DATA packet out of replyDG
        wrong blocknum:
                continue
        // now we have a good packet!
                write data
   
            if
expected_block == 1, set destport = replyDG.getport()
                expected_block ++;
                send ACK to destport
                if (size < 512) {                         dally();            // to be discussed                         break;            // done                 } } Now on to the timeout issue. There are two different uses of the term here. Suppose the timeout period is, say, 3000 ms. A SocketTimeoutException, meaning that the socket received nothing at all for 3000 ms. Let's call this a "hard timeout". It's time to resend. We are expecting Data[N] and haven't received it for at least 3000 ms (though we may have received other things). Let's call this a "soft timeout". It should be clear that a hard timeout does imply a soft timeout: if you've received nothing, then you certainly haven't received the packet you were waiting for. However, the converse is not true! It is possible for you to receive a steady stream of "noise" packets, that serve to prevent a hard timeout from ever occuring, but because none of them is the correct packet you still have to have a soft timeout. The only way to resolve this is to check for the elapsed time. The current time is always available in System.currentTimeMillis(); you will save that value each time you send a packet:         send_time = System.currentTimeMillis(); Now, the first solution to the soft-timeout problem is to check someplace before any "continue" statements that the elapsed time has not been exceeded. That works, but it turns out that a better solution is to notice that if you check elapsed time for soft timeouts, you no longer really need to do anything for hard timeouts (except restart the loop). The hard-timeout interval becomes the clock granularity, in effect: if the soft-timeout interval is 3000 ms and the hard-timeout interval is 1000 ms, then in the worst case you wait until 3000+1000 = 4000 ms before actually noticing and responding to the soft timeout. Once you have an elapsed-time check, it makes sense to shorten the hard-timeout interval to something very small; 1000 ms or even 250 ms. On every "hard" timeout you check the elapsed time for a "soft" timeout. At this point, a (short) hard timeout no longer implies a (long) soft timeout. Note that, although the elapsed-time check is at the beginning of the loop here, it's never executed immediately after receiving a valid packet because after receiving a valid packet we always update send_time, and the elapsed-time check will then fail until we've had at least once attempt at s.receive(). In other words, you don't need a flag or any special logic to prevent checking the elapsed time immediately after sending: it's harmless then. send REQ send_time = System.currentTimeMilllis(); while (true) {         check elapsed time: if exceeded (ie if a soft timeout),                 resend whatever was sent most recently                 send_time = System.currentTimeMilllis();         replyDG = s.receive()    // possibly a timeout         if HARD_TIMEOUT:                 do nothing!                 continue         wrong IP addr:                 continue         wrong port:            // really separate from wrong IP-addr                 send error packet                 continue         wrong length:    // can't even check for DATA opcode if there aren't enough bytes!                 continue         not DATA                 continue         create DATA packet out of replyDG         wrong blocknum:                 continue         // now we have a good packet!                 write data                 expected_block ++;                 send ACK to destport                 send_time = System.currentTimeMilllis();                                if (size < 512) {                         dally();            // to be discussed                         break;            // done                 } }

Still stressed with your coursework?
Get quality coursework help from an expert!