Out-of-order and packet loss of Java Datagram

Source: Internet
Author: User
The out-of-order and packet loss of Java Datagram-general Linux technology-Linux programming and kernel information. The following is a detailed description. Accustomed to TCP programming, it is wrong to think that UDP can handle these problems. A udp application must take full responsibility for reliability, including packet loss, duplication, latency, out-of-order, and connection failure.

Generally, we develop and test on a LAN with good reliability and low transmission latency. Some problems are not easy to expose, but errors may occur on the large Internet.

The UDP protocol pushes the responsibility for delivery reliability to the upper layer, that is, the application layer. below, several classes are compiled to specifically deal with two problems: out-of-order and packet loss.

Four classes: DataPacket class, PacketHeader class, PacketBody class, And DataEntry class, which are located in the same file DataPacket. java.

The DataPacket class is equivalent to a facade mode and is provided for external use. Communication Data is also processed in this class.

Package com. skysoft. pcks;

Import java. io .*;
Import java.net .*;
Import java. util .*;

Public class DataPacket {
InputStream is;
OutputStream OS;
PacketHeader;
PacketBody body;
ArrayList al;
Public static final int DataSwapSize = 64532;

/**
* Used to receive a Datagram
*/
Public DataPacket (){
Header = new PacketHeader ();
Body = new PacketBody ();
Al = new ArrayList ();
}
/**
* Used to send data reports. It calls the message segmentation operation.
* @ Param file String hard drive file
*/
Public DataPacket (String file ){
This ();
Try {
Is = new FileInputStream (file );
Header. CalcHeaderInfo (is. available ());
This. madeBody ();
Is. close ();
// This. Gereratedata ();
}
Catch (FileNotFoundException ex ){
Ex. printStackTrace ();
}
Catch (IOException ex1 ){
Ex1.printStackTrace ();
}
}
/**
* Used to send data reports. It calls the message segmentation operation.
* @ Param url URL
*/
Public DataPacket (URL url ){
This ();
Try {
// Is = url. openStream ();
URLConnection conn = url. openConnection ();
Is = conn. getInputStream ();
Int total = conn. getContentLength ();
Header. CalcHeaderInfo (total );
This. madeBody ();
// System. out. println (total + ":" + total );
Is. close ();
}
Catch (IOException ex ){
Ex. printStackTrace ();
}
}
/**
* For the sending construction group, the PackageHeader is used to process the Header Format and serial number of the grouping.
*/
Private void madeBody (){
Al. clear ();
Byte [] buffer;
DataEntry de;
For (int I = 0; I Try {
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
// Is. skip (I * body. BODY_BUFFER_SIZE );
Header. ArrageSort (I );
De = new DataEntry (PacketBody. BODY_BUFFER_SIZE );
De. setSn (I );
De. setStreamsize (header. getStreamsize ());
De. setFragmentcounter (header. getFragmentcounter ());
If (header. isWTailFragment (I )){
Buffer = new byte [header. getMinfragment ()];
Is. read (buffer, 0, buffer. length );
Header. setActByteSize (header. getMinfragment ());
De. setActByteSize (header. getMinfragment ());
}
Else {
Buffer = new byte [body. BODY_BUFFER_SIZE];
Is. read (buffer, 0, buffer. length );
}
// System. out. println ("length -------" + I + "" + body. getBody (). length + "" + header. getMinfragment ());
Body. setBody (buffer );
// System. out. println ("length:" + I + "" + header. toString ());
Bos. write (header. getByte (), 0, header. HEADER_BUFFER_SIZE );
Bos. write (body. getBody (), 0, body. getBody (). length );
De. setBytes (bos. toByteArray ());
Al. add (de );
}
Catch (IOException ex ){
Ex. printStackTrace ();
}
}
}
/**
* Creates a group for sending. the header format is not taken into account and no serial number is produced for the grouping.
*/
Private void madeBody1 (){
Al. clear ();
For (int I = 0; I Try {
If (header. isWTailFragment (I ))
Is. read (body. getBody (), I * body. BODY_BUFFER_SIZE,
Header. getMinfragment ());
Else
Is. read (body. getBody (), I * body. BODY_BUFFER_SIZE,
Body. BODY_BUFFER_SIZE );
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
Bos. write (header. getByte (), 0, header. HEADER_BUFFER_SIZE );
Bos. write (body. getBody (), header. HEADER_BUFFER_SIZE,
Body. getBody (). length );
Al. add (bos );
}
Catch (IOException ex ){
Ex. printStackTrace ();
}
}
}
/**
* After receiving a packet, the packet is assembled to handle packet loss and out-of-order.
* @ Param b1 byte []
*/
Public void Add (byte [] b1 ){
Byte [] buffer = (byte []) b1.clone ();
HandlerText (buffer );
DataEntry de = new DataEntry (buffer, header. getActByteSize ());
De. setSn (header. getSn ());
De. setStreamsize (header. getStreamsize ());
De. setFragmentcounter (header. getFragmentcounter ());
Al. add (de );
}
Private void handlerText (byte [] buffer ){
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
Baos. write (buffer, 0, header. HEADER_BUFFER_SIZE );
Byte [] B = new byte [header. HEADER_BUFFER_SIZE];
System. arraycopy (buffer, 0, B, 0, B. length );
ByteArrayInputStream bais = new ByteArrayInputStream (baos. toByteArray ());
InputStreamReader isr = new InputStreamReader (bais );
BufferedReader br = new BufferedReader (isr );
Try {
Header = new PacketHeader (br. readLine ());
}
Catch (Exception ex ){
Ex. printStackTrace ();
}
}

Private String calFileSize (int size ){
Return size/1024 + "K ";
}

Public ArrayList getDataPackets (){
Return al;
}
/**
* Whether the receipt is complete, determined by whether the serial number is equal to the maximum segment number. This may be a problem. For example, the last segment is lost.
* The entire package is lost.
* @ Return
*/
Public boolean isFull (){
Return this. header. getSn () = this. header. getFragmentcounter ()-1? True: false;
}
/**
* Judge whether there is only one segment.
* @ Return
*/
Public boolean isZero (){
Return this. header. getSn () = 0? True: false;
}
/**
* This function executes Message Assembly, regardless of the lost message.
* @ Return
*/
Private ByteArrayOutputStream fetchDataPackets (){
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
Byte [] buffer = null;
DataEntry de;
For (int I = 0; I <al. size (); I ++ ){
Try {
De = this. getSnData (I );
Buffer = de. getByte ();
If (header. getStreamsize () = de. getStreamsize ()){
Bos. write (de. getByte (), header. HEADER_BUFFER_SIZE, de. getActByteSize ());
System. out. println (de. toString () + "-- fetchDataPackets ");
}
}
Catch (Exception ex ){
Ex. printStackTrace ();
}
}
Return bos;
}

/**
* This function is used to assemble messages. For lost messages, empty messages are written.
* @ Return ByteArrayOutputStream
*/
Private ByteArrayOutputStream fetchDataPackets_sn (){
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
Byte [] buffer;
DataEntry de;
For (int I = 0; I Try {
De = this. getSnData (I );
If (de = null ){
De = seachDeData (I );
}
Buffer = de. getByte ();
// System. out. println (de. getSn () + ":" + I );
// HandlerText (buffer );
// Bos. write (buffer, header. HEADER_BUFFER_SIZE,
// Buffer. length-header. HEADER_BUFFER_SIZE );
If (header. getStreamsize () = de. getStreamsize ()){
Bos. write (de. getByte (), header. HEADER_BUFFER_SIZE,
De. getActByteSize ());
// System. out. println (de. toString ());
}
}
Catch (Exception ex ){
Ex. printStackTrace ();
}
}
Return bos;
}

/**
* Sort the buffered data packets, that is, extract data of the same frame in sequence. If no frame of the serial number is found, a null value is returned.
* @ Param sn int indicates the sequence number of the frame to be searched.
* @ Return DataEntry
*/
Private DataEntry getSnData (int sn ){
DataEntry de = null;
For (int I = 0; I <al. size (); I ++ ){
De = (DataEntry) al. get (I );
If (header. getStreamsize () = de. getStreamsize ()){
If (sn = de. getSn ())
Break;
Else
De = null;
}
}
Return de;
}

/**
* Start to search for the nearest frame segment forward or backward by sequence number. In the future, you can add the request resend function to enable a communication connection.
* @ Param sn int
* @ Return DataEntry
*/
Private DataEntry seachDeData (int sn ){
DataEntry de = null;
Int initvalue, minvalue = 10000;
DataEntry back, fore = null;
For (int I = 0; I <al. size (); I ++ ){
De = (DataEntry) al. get (I );
If (header. getStreamsize () = de. getStreamsize ()){
Initvalue = Math. abs (de. getSn ()-sn );
If (de. getFragmentcounter ()! = De. getSn () & initvalue <minvalue ){
Minvalue = initvalue;
Fore = de;
}
}
}
Return fore;
}

/**
* Except the last frame, one frame is randomly selected.
* @ Return DataEntry
*/
Private DataEntry seachDeData (){
DataEntry de = null;
For (int I = 0; I <al. size (); I ++ ){
De = (DataEntry) al. get (I );
System. out. println ("sky:" + de. getFragmentcounter () + ":" + de. getSn () +
":" + I );
If (header. getStreamsize () = de. getStreamsize ()){
If (de. getFragmentcounter ()! = De. getSn ()){
Break;
}
}
}
Return de;
}
/**
* Generate the assembled result data. Because the image is used for testing, it is returned to the image.
* @ Return Image
*/
Public java. awt. Image Gereratedata (){
ByteArrayInputStream bis;
Java. awt. image. BufferedImage bimage = null;
Try {
Byte [] B = fetchDataPackets_sn (). toByteArray ();
// FetchDataPackets_old1 ()
Bis = new ByteArrayInputStream (B );
Bimage = javax. imageio. ImageIO. read (bis );

}
Catch (Exception ex1 ){
Ex1.printStackTrace ();
}
Return bimage;
}

Public static void main (String args []) {
DataPacket dp = new DataPacket ("e: \ nature \ 14.jpg ");
}
}
/**
* The data entity acts as a temporary processing place.
* @ Author Administrator
*
*/
Class DataEntry {
Byte [] bytes;
Int fragmentcounter, sn, actbytesize;
Long streamsize;
Int minfragment;

Public DataEntry (){

}

Public DataEntry (int size ){
This. actbytesize = size;
}

Public DataEntry (byte [] B, int I ){
This. bytes = B;
This. actbytesize = I;
}

Public byte [] getByte (){
Return this. bytes;
}

Public void setBytes (byte [] B ){
This. bytes = B;
}

Public void setStreamsize (long size ){
This. streamsize = size;
}

Public long getStreamsize (){
Return this. streamsize;
}

Public int getMinfragment (){
Return minfragment;
}

Public synchronized void setSn (int I ){
This. sn = I;
}

Public synchronized int getSn (){
Return sn;
}

Public synchronized int getFragmentcounter (){
Return fragmentcounter;
}

Public synchronized void setFragmentcounter (int c ){
This. fragmentcounter = c;
}

Public void setActByteSize (int size ){
Actbytesize = size;
}

Public int getActByteSize (){
Return actbytesize;
}

Public String toString (){
Return this. streamsize + ":" + this. fragmentcounter + ":" + this. sn +
":" + This. actbytesize + "recv DataEntry ";
}
}
/**
* Header, processing Header Format
* @ Author Administrator
*
*/
Class PacketHeader implements Serializable {
Public static final int HEADER_BUFFER_SIZE = 1024;
Int fragmentcounter, sn;
Int actbytesize = PacketBody. BODY_BUFFER_SIZE;
Byte [] header; // = new byte [HEADER_BUFFER_SIZE];
Long streamsize;
Int minfragment;

Public PacketHeader (){

}

Public PacketHeader (long l ){
This. setStreamsize (l );

}

Public PacketHeader (String s ){
String [] tm = s. split ("::");
This. setActByteSize (Integer. parseInt (tm [3]);
This. setSn (Integer. parseInt (tm [2]);
This. setFragmentcounter (Integer. parseInt (tm [1]);
This. setStreamsize (Long. parseLong (tm [0]);
}

/**
* Generate a data header Based on the sequence of file segments.
* @ Param sn file Sequence
*/
Public void ArrageSort (int sn ){
This. setSn (sn );
This. setByte ();
}

Public void CalcHeaderInfo (long l ){
This. setStreamsize (l );
CalcHeaderInfo ();
}
/**
* Calculate the number of segments to be divided into and obtain the minimum margin.
*/
Public void CalcHeaderInfo (){
Fragmentcounter = Math. round (float) streamsize/
PacketBody. BODY_BUFFER_SIZE );
Float critical = (float) streamsize/PacketBody. BODY_BUFFER_SIZE;
If (critical-fragmentcounter <0.5 & critical-fragmentcounter> 0)
Fragmentcounter ++;
Minfragment = (int) (streamsize % PacketBody. BODY_BUFFER_SIZE );
}

Public byte [] getHeader (){
Long it = new Long (this. streamsize );
Return new byte [] {it. byteValue ()};
}

Public byte [] getByte (){
Return header; // this. toString (). getBytes ();
}
/**
* Generate a header byte. First, obtain the size of the header stream: number of segments: Segment sequence: bytes of the actual size of the segment,
* Add the carriage return newline character. For the remaining part of the 1024 bytes, the array of bytes whose element is 0 will be written.
*/
Public void setByte (){
ByteArrayOutputStream bos = new ByteArrayOutputStream ();
Byte [] buffer = this. toByte ();
Try {
Bos. write (buffer );
Bos. write ("\ r \ n". getBytes ());
Bos. write (new byte [PacketHeader. HEADER_BUFFER_SIZE-buffer. length], 0,
PacketHeader. HEADER_BUFFER_SIZE-buffer. length );
Header = bos. toByteArray ();
}
Catch (IOException ex ){
Ex. printStackTrace ();
}
}

Public void setStreamsize (long size ){
This. streamsize = size;
}

Public long getStreamsize (){
Return this. streamsize;
}

Public int getMinfragment (){
Return minfragment;
}

Public synchronized void setSn (int I ){
This. sn = I;
}

Public int getSn (){
Return sn;
}

Public int getFragmentcounter (){
Return fragmentcounter;
}

Public synchronized void setFragmentcounter (int c ){
This. fragmentcounter = c;
}

Public void setActByteSize (int size ){
Actbytesize = size;
SetByte ();
}

Public int getActByteSize (){
Return actbytesize;
}
/**
* The format of the data packet header is: stream size: number of segments: Segment sequence: actual segment size
* The length of the header byte can be changed. For example, you can add the specific information of the stream, such as the name of the file to which the stream belongs, the file type, and other information.
* @ Return String
*/
Public String toString (){
Return streamsize + ":" + this. fragmentcounter + ":" + this. getSn () +
":" + This. getActByteSize ();
}

Public byte [] toByte (){
Return this. toString (). getBytes ();
}
/**
* Is it a tail segment?
* @ Param I int
* @ Return boolean
*/
Public boolean isWTailFragment (int I ){
Return (I = fragmentcounter-1 )? True: false;
}

}
/**
* User Data Zone
* @ Author Administrator
*
*/
Class PacketBody implements Serializable {
Public static final int BODY_BUFFER_SIZE = 63508; // 65508
Byte [] body;

Public PacketBody (){
}

Public void setBody (byte [] B ){
This. body = B;
}

Public byte [] getBody (){
Return body;
}
}

This data processing class will be used later.
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.