Java数据报之失序和丢包.docx
《Java数据报之失序和丢包.docx》由会员分享,可在线阅读,更多相关《Java数据报之失序和丢包.docx(11页珍藏版)》请在冰豆网上搜索。
![Java数据报之失序和丢包.docx](https://file1.bdocx.com/fileroot1/2023-1/26/17a512e2-6f2f-4200-9f2b-3eee7afe4a4c/17a512e2-6f2f-4200-9f2b-3eee7afe4a4c1.gif)
Java数据报之失序和丢包
Java数据报之失序和丢包
习惯了TCP编程,认为UDP可以包办这些问题是错误的。
一个UDP应用程序要承担可靠性方面的全部工作,包括报文的丢失、重复、时延、乱序以及连接失效等问题。
通常我们在可靠性好,传输时延小的局域网上开发测试,一些问题不容易暴露,但在大型互联网上却会出现错误。
UDP协议把递送的可靠性责任推到了上层即应用层,下面简单编写了几个类来专门处理两个问题:
乱序和丢包。
四个类:
DataPacket类,PacketHeader类,PacketBody类,DataEntry类,位于同一个文件DataPacket.java中。
DataPacket类相当于一个门面模式,提供给外部使用,通信数据也在这个类中处理。
packagecom.skysoft.pcks;
importjava.io.*;
import.*;
importjava.util.*;
publicclass DataPacket{
OutputStreamos;
PacketHeaderheader;
PacketBodybody;
ArrayListal;
publicstaticfinalintDataSwapSize=64532;
/**
*在接收数据报使用
*/
publicDataPacket(){
header=newPacketHeader();
body=newPacketBody();
al=newArrayList();
}
/**
*在发送数据报时使用,它调用报文分割操作.
*@paramfileString 硬盘文件
*/
publicDataPacket(Stringfile){
this();
try{
is=newFileInputStream(file);
header.CalcHeaderInfo(is.available());
this.madeBody();
is.close();
//this.Gereratedata();
}
catch(FileNotFoundExceptionex){
ex.printStackTrace();
}
catch(IOExceptionex1){
ex1.printStackTrace();
}
}
/**
*在发送数据报时使用,它调用报文分割操作.
*@paramurlURLurl地址
*/
publicDataPacket(URLurl){
this();
try{
//is=url.openStream();
URLConnectionconn=url.openConnection();
is=conn.getInputStream();
inttotal=conn.getContentLength();
header.CalcHeaderInfo(total);
this.madeBody();
//System.out.println(total+":
"+total);
is.close();
}
catch(IOExceptionex){
ex.printStackTrace();
}
}
/**
*为发送构造分组,使用PackageHeader处理了报头格式,并为分组编序号.
*/
privatevoidmadeBody(){
al.clear();
byte[]buffer;
DataEntryde;
for(inti=0;i< header.fragmentcounter;i++){
try{
ByteArrayOutputStreambos=newByteArrayOutputStream();
//is.skip(i*body.BODY_BUFFER_SIZE);
header.ArrageSort(i);
de=newDataEntry(PacketBody.BODY_BUFFER_SIZE);
de.setSn(i);
de.setStreamsize(header.getStreamsize());
de.setFragmentcounter(header.getFragmentcounter());
if(header.isWTailFragment(i)){
buffer=newbyte[header.getMinfragment()];
is.read(buffer,0,buffer.length);
header.setActByteSize(header.getMinfragment());
de.setActByteSize(header.getMinfragment());
}
else{
buffer=newbyte[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(IOExceptionex){
ex.printStackTrace();
}
}
}
/**
*为发送构造分组,没有考虑报头格式,也没有为分组编序号.
*/
privatevoidmadeBody1(){
al.clear();
for(inti=0;i< header.fragmentcounter;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);
ByteArrayOutputStreambos=newByteArrayOutputStream();
bos.write(header.getByte(),0,header.HEADER_BUFFER_SIZE);
bos.write(body.getBody(),header.HEADER_BUFFER_SIZE,
body.getBody().length);
al.add(bos);
}
catch(IOExceptionex){
ex.printStackTrace();
}
}
}
/**
*在接收到报文后,对此报文执行组装,并处理报文丢失和乱序情况.
*@paramb1byte[]
*/
publicvoidAdd(byte[]b1){
byte[]buffer=(byte[])b1.clone();
handlerText(buffer);
DataEntryde=newDataEntry(buffer,header.getActByteSize());
de.setSn(header.getSn());
de.setStreamsize(header.getStreamsize());
de.setFragmentcounter(header.getFragmentcounter());
al.add(de);
}
privatevoidhandlerText(byte[]buffer){
ByteArrayOutputStreambaos=newByteArrayOutputStream();
baos.write(buffer,0,header.HEADER_BUFFER_SIZE);
byte[]b=newbyte[header.HEADER_BUFFER_SIZE];
System.arraycopy(buffer,0,b,0,b.length);
ByteArrayInputStreambais=newByteArrayInputStream(baos.toByteArray());
InputStreamReaderisr=newInputStreamReader(bais);
BufferedReaderbr=newBufferedReader(isr);
try{
header=newPacketHeader(br.readLine());
}
catch(Exceptionex){
ex.printStackTrace();
}
}
privateStringcalFileSize(intsize){
returnsize/1024+"K";
}
publicArrayListgetDataPackets(){
returnal;
}
/**
*是否接收完毕,通过序号是否等于最大段数来判断,这也许有问题,比如,正好是最后一个段丢失了,这样
*这个包整个就丢失了.
*@return
*/
publicbooleanisFull(){
returnthis.header.getSn()==this.header.getFragmentcounter()-1?
true:
false;
}
/**
*判断是否只有一个段.
*@return
*/
publicbooleanisZero(){
returnthis.header.getSn()==0?
true:
false;
}
/**
*该函数执行报文组装,不考虑丢失的报文.
*@return
*/
privateByteArrayOutputStreamfetchDataPackets(){
ByteArrayOutputStreambos=newByteArrayOutputStream();
byte[]buffer=null;
DataEntryde;
for(inti=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(Exceptionex){
ex.printStackTrace();
}
}
returnbos;
}
/**
*该函数执行报文组装,对于丢失的报文,写入空报文.
*@returnByteArrayOutputStream
*/
privateByteArrayOutputStreamfetchDataPackets_sn(){
ByteArrayOutputStreambos=newByteArrayOutputStream();
byte[]buffer;
DataEntryde;
for(inti=0;i< header.getFragmentcounter();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(Exceptionex){
ex.printStackTrace();
}
}
returnbos;
}
/**
*对缓冲的数据包进行排序处理,即按顺序提取同一帧的数据,如果没有找到该序号的帧,则返回空值.
*@paramsnint要找的帧序号.
*@returnDataEntry
*/
privateDataEntrygetSnData(intsn){
DataEntryde=null;
for(inti=0;i< al.size();i++){
de=(DataEntry)al.get(i);
if(header.getStreamsize()==de.getStreamsize()){
if(sn==de.getSn())
break;
else
de=null;
}
}
returnde;
}
/**
*按序号开始向前或者是向后寻找最近的帧片段,日后可以增加请求重发功能,通过开一个通信连接.
*@paramsnint
*@returnDataEntry
*/
privateDataEntryseachDeData(intsn){
DataEntryde=null;
intinitvalue,minvalue=10000;
DataEntryback,fore=null;
for(inti=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;
}
}
}
returnfore;
}
/**
*除去最后一帧外,随机抽取一帧.
*@returnDataEntry
*/
privateDataEntryseachDeData(){
DataEntryde=null;
for(inti=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;
}
}
}
returnde;
}
/**
*生成组装完的结果数据.因为用图像来做测试,所以令其返回图像.
*@returnImage
*/
publicjava.awt.ImageGereratedata(){
ByteArrayInputStreambis;
java.awt.image.BufferedImagebimage=null;
try{
byte[]b=fetchDataPackets_sn().toByteArray();
//fetchDataPackets_old1()
bis=newByteArrayInputStream;
bimage=javax.imageio.ImageIO.read(bis);
}
catch(Exceptionex1){
ex1.printStackTrace();
}
returnbimage;
}
publicstaticvoidmain(Stringargs[]){
DataPacketdp=newDataPacket("e:
\\nature\\14.jpg");
}
}
/**
*数据实体,充当临时处理场所.
*@authorAdministrator
*
*/
classDataEntry{
byte[]bytes;
intfragmentcounter,sn,actbytesize;
longstreamsize;
intminfragment;
publicDataEntry(){
}
publicDataEntry(intsize){
this.actbytesize=size;
}
publicDataEntry(byte[]b,inti){
this.bytes=b;
this.actbytesize=i;
}
publicbyte[]getByte(){
returnthis.bytes;
}
publicvoidsetBytes(byte[]b){
this.bytes=b;
}
publicvoidsetStreamsize(longsize){
this.streamsize=size;
}
publiclonggetStreamsize(){
returnthis.streamsize;
}
publicintgetMinfragment(){
returnminfragment;
}
publicsynchronizedvoidsetSn(inti){
this.sn=i;
}
publicsynchronizedintgetSn(){
returnsn;
}
publicsynchronizedintgetFragmentcounter(){
returnfragmentcounter;
}
publicsynchronizedvoidsetFragmentcounter(intc){
this.fragmentcounter=c;
}
publicvoidsetActByteSize(intsize){
actbytesize=size;
}
publicintgetActByteSize(){
returnactbytesize;
}
publicStringtoString(){
returnthis.streamsize+":
:
"+this.fragmentcounter+":
:
"+this.