Android 客户端:
1. 创建Socket对象
Socket socket = new Socket();
2.创建连接到指定的主机、端口
socket.connect(new InetSocketAddress("10.10.10.100", 980));
3.创建File对像,并指定要传输的文件绝对路径
File f=new File("/sdcard2/AppManage.apk");
如果需要用断点继传需要用这个RandomAccessFile对象
//RandomAccessFile fileOutStream = new RandomAccessFile(f, "r");
//"r":以只读文方式打开指定文件。如果你写的话会有IOException。
//"rw":以读写方式打开指定文件,不存在就创建新文件。
4.将文件绑定到InputStream流对象
InputStream fileOutStream = new FileInputStream(f);
5.创建OutputStream对象
OutputStream outputStream = socket.getOutputStream();
如果需要用断点继传需在这里设定跳过的字节。
//fileOutStream.seek(sek);
6.获取文件总长度
long count = fileOutStream.available();
上面可能读不到文件的总长度,因为读取时需要时间,如果SD卡质量不好可能要等待一会。
所以最好加上这一句
while(count == 0){
count = fileOutStream.available();
}
如果是用断点继传用这个获取文件总长度
long count = fileOutStream.length();
7. 将文件总字节数写入到流中,这里要做一个long转成8个字节的转换
byte[] totalCount = new byte[8]; //将总数转为byte字符
outputStream.write(totalCount);
8. 指定每包大小字节和计算包数 -2,147,483,648 到 2,147,483,647
int PacketSize = 10240;//这里指定每包为10Kbyte
int PacketCount = (int)(count / ((long)PacketSize));//总包数
int LastDataPacket = (int)(count - ((long)(PacketSize * PacketCount)));//余字节数,也可能会是0
9.循环将包写入到流中
byte[] buffer = new byte[PacketSize];//设定缓冲区
for(int i=0; i<PacketCount; i++){
fileOutStream.read(buffer,0,buffer.length);//将文件读到缓冲区
byte[] bufferLength = new byte[4]//需要将buffer的长度转换为byte字节
outputStream.write(bufferLength);//写入4个字节代表buffer的长度
outputStream.write(buffer);//将缓冲写入到流
}
10.写入余字节数
if(LastDataPacket != 0){
buffer = new byte[LastDataPacket];//重新设定缓冲区大小
fileOutStream.read(buffer,0,buffer.length);将文件读到缓冲区
byte[] bufferLength = new byte[4]//需要将buffer的长度转换为byte字节
outputStream.write(bufferLength);//写入4个字节代表buffer的长度
outputStream.write(buffer);//将缓冲写入到流
}
11. 最后关闭和刷新
outputStream.flush();
fileOutStream.close();
outputStream.close();
需要注意的是,如果未按7章中写入文件总字节到流中服务器就不会知道文件的大小,导致只能一直接收并写入到文件中,并且
需要客户端关闭时才会停止,没办法回复信息。
服务器端(用C#写的服务器端),主要解释将流写入到文件
1.创建文件对象FileStream
FileStream MyFileStream = new FileStream("保存路径", FileMode.Create, FileAccess.Write);
如果是断点继传,需要用下面的方式
FileStream MyFileStream = new FileStream("保存路径", FileMode.Append, FileAccess.Write);
MyFileStream.Seek(0, SeekOrigin.Begin);
2.读取文件总字节
byte[] total = new byte[8];//创建缓冲区
Receive(total, 0, 8, SocketFlags.None);//读到8个字节位置
long totalCoun = BitConverter.ToInt64(total, 0);//转换成long
3.循环读取流并写入到文件
while (true) {
//循环读取,每次读到包指定位置
byte[] data = ReceiveVarData(client);
if (data.Length == 0) {
break;//读取0时退出
} else {
//写入到文件中
MyFileStream.Write(data, 0, data.Length);
}
}
//关闭
MyFileStream.Close();
最后是ReceiveVarData的方法,也是关键部份
public byte[] ReceiveVarData(Socket s){
int total = 0;
int recv;
byte[] datasize = new byte[4];//创建缓冲区
recv = s.Receive(datasize, 0, 4, SocketFlags.None);//读到4个字节位置
int size = BitConverter.ToInt32(datasize, 0);//转换为int
int dataleft = size;
byte[] data = new byte[size];//创建当前要接收的大小缓冲区
因为网络可能会堵塞,这里也要做循环判断。
while (total < size) {
recv = s.Receive(data, total, dataleft, SocketFlags.None);//开始读取
if (recv == 0) {
data = null;
break;
}
total += recv;
dataleft -= recv;
}
return data;
}