虽然TCP协议是可靠传输协议,但是,在服务器端,接受缓冲总是有限的,因此,如果不将数据进行分包发送,在传送的过程中,就无法判断接受到的数据是上一次还没发完的部分,还是新发送的数据。同时,为了更方便地对接收到的数据根据不同的类型进行设计,需要将发送的数据的类型添加到要发送的数据中去,根据上面的两个方面的原因,需要在数据分包发送,并且加入包头。
数据包的设计如下:
由于在Java中,使用TCP Socket发送的时候,我使用的是BufferedOutputStream作为输出缓冲的,因此,发送的部分只能是byte数组,因此,必须将数据包中的int类型的变量转化为byte数组存储和发送,这个可以参考我前面的博客Java 将byte[] 与int类型互相转换 ,为了方便起见,我把数据包封装成一个单独的类,并且在类中定义了用于将数据包的头部和数据内容打包成一个byte数据的方法,同时,也定义了一个将byte数组解包的函数。有了这些函数,就可以一个数据包一个数据包地接收数据了。
具体的代码如下:
package edu.pkusz.sheng;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
/**
*
*/
/**
* @author sheng
*
*/
public class DataPackage
{
//
protected boolean IsReceiver = false;
// The file header
protected PackageType Type = null;
protected int NumberOfPackages = 0;
protected int IndexOfPackages = 0;
protected int SizeOfData = 0;
// The content of the data
protected byte[] Content = null;
public DataPackage(boolean IsReceiver)
{
this.IsReceiver = IsReceiver;
}
public PackageType GetType()
{
if (IsReceiver == true)
{
return this.Type;
}
return PackageType.NULLTYPE;
}
public int GetNumberOfPackages()
{
if (IsReceiver == true)
{
return this.NumberOfPackages;
}
return 0;
}
public int GetIndexOfPackages()
{
if (IsReceiver == true)
{
return this.IndexOfPackages;
}
return 0;
}
public int GetSizeOfData()
{
if (IsReceiver == true)
{
return this.SizeOfData;
}
return 0;
}
public byte[] GetContent()
{
if (IsReceiver == true)
{
return this.Content;
}
return null;
}
public boolean SetType(PackageType Type)
{
if (IsReceiver == false)
{
this.Type = Type;
return true;
}
return false;
}
public boolean SetNumberOfPackages(int NumberOfPackages)
{
if (IsReceiver == false)
{
this.NumberOfPackages = NumberOfPackages;
return true;
}
return false;
}
public boolean SetIndexOfPackages(int IndexOfPackages)
{
if (IsReceiver == false)
{
this.IndexOfPackages = IndexOfPackages;
return true;
}
return false;
}
public boolean SetSizeOfData(int SizeOfData)
{
if (IsReceiver == false)
{
this.SizeOfData = SizeOfData;
return true;
}
return false;
}
public boolean SetContent(byte[] Content)
{
if (IsReceiver == false)
{
this.Content = Content;
return true;
}
return false;
}
//
protected byte[] Packing()
{
byte[] packageData = new byte[BufferSize.PACKAGEHEADERSIZE + SizeOfData];
byte [] Tmp;
int Offset = 0;
// The file type
Tmp = Converter.ConvertIntToByteArray(Type.ordinal());
System.arraycopy(Tmp, 0, packageData, Offset, BufferSize.INTSIZE);
Offset += BufferSize.INTSIZE;
// The NumberOfPackages
Tmp = Converter.ConvertIntToByteArray(NumberOfPackages);
System.arraycopy(Tmp, 0, packageData, Offset, BufferSize.INTSIZE);
Offset += BufferSize.INTSIZE;
// The IndexOfPackages
Tmp = Converter.ConvertIntToByteArray(IndexOfPackages);
System.arraycopy(Tmp, 0, packageData, Offset, BufferSize.INTSIZE);
Offset += BufferSize.INTSIZE;
// The DataSize
Tmp = Converter.ConvertIntToByteArray(SizeOfData);
System.arraycopy(Tmp, 0, packageData, Offset, BufferSize.INTSIZE);
Offset += BufferSize.INTSIZE;
// Content
System.arraycopy(Content, 0, packageData, Offset, SizeOfData);
return packageData;
}
protected boolean Unpacking(byte[] Data, int Lenth)
{
byte [] Tmp = new byte[BufferSize.INTSIZE];
int Offset = 0;
// Package Type
System.arraycopy(Data, Offset, Tmp, 0, BufferSize.INTSIZE);
this.Type = PackageType.values()[Converter.ConvertByteArrayToInt(Tmp)];
Offset += BufferSize.INTSIZE;
// The NumberOfPackages
System.arraycopy(Data, Offset, Tmp, 0, BufferSize.INTSIZE);
this.NumberOfPackages = Converter.ConvertByteArrayToInt(Tmp);
Offset += BufferSize.INTSIZE;
// The Index of Packages
System.arraycopy(Data, Offset, Tmp, 0, BufferSize.INTSIZE);
this.IndexOfPackages = Converter.ConvertByteArrayToInt(Tmp);
Offset += BufferSize.INTSIZE;
// The SizeOfData
System.arraycopy(Data, Offset, Tmp, 0, BufferSize.INTSIZE);
this.SizeOfData = Converter.ConvertByteArrayToInt(Tmp);
Offset += BufferSize.INTSIZE;
// System.out.println("The number of package is " + this.NumberOfPackages);
// System.out.println("The index of package is " + this.IndexOfPackages);
// System.out.println("The size of data is " + this.SizeOfData);
// The content
this.Content = new byte[this.SizeOfData];
System.arraycopy(Data, Offset, this.Content, 0, SizeOfData);
return true;
}
public boolean Send(BufferedOutputStream OutputStream)
{
// TODO Auto-generated method stub
if (IsReceiver == false)
{
int PackageSize = BufferSize.PACKAGEHEADERSIZE + SizeOfData;
byte [] TmpData = Packing();
byte [] SendData = null;
// 当数据包的大小小于缓冲区的大小时,填充数据包
if (BufferSize.BUFFERSIZE > PackageSize)
{
SendData = new byte[BufferSize.BUFFERSIZE];
System.arraycopy(TmpData, 0, SendData, 0, PackageSize);
}
else //当数据包的大小等于缓冲区的时候,不做其他处理
{
SendData = TmpData;
}
try {
OutputStream.write(SendData, 0, BufferSize.BUFFERSIZE);
OutputStream.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
else
{
return false;
}
}
public int Receive(BufferedInputStream InputStream)
{
// TODO Auto-generated method stub
if (IsReceiver == true)
{
byte[] Data = new byte[BufferSize.BUFFERSIZE];
int Len = 0;
try
{
Len = InputStream.read(Data);
} catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
// System.out.println("The len of data is " + Len);
if (Unpacking(Data, Len))
{
return Len;
}
return 0;
}
else
{
return 0;
}
}
public boolean SaveContent(BufferedOutputStream OutputFile)
{
if (IsReceiver == true)
{
// TODO Auto-generated method stub
try
{
OutputFile.write(Content, 0, this.SizeOfData);
OutputFile.flush();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
}
else
{
return false;
}
}
}