通过Socket连接一次传输多个文件
近期在做一个通过WIFI在手机之间传输文件的功能。须要在手机之间建立一个持久的Socket
连接并利用该连接数据传输。能够一次传输一个或多个文件。
在一次传输多个文件时,遇到了一个困难:怎样在接收文件时确定文件之间的边界。
为了在接收端正确的拆分文件,在传输文件时须要传输每一个文件的大小。
我採用了这样一种策略:首先发送每一个文件的名称和大小。然后传输文件的内容。
protected void sendFile(Socket socket, File[] files) {
long totalSize = 0;
byte buf[] = new byte[8192];
int len;
try {
if (socket.isOutputShutdown()) {
return;
}
DataOutputStream dout = new DataOutputStream(
socket.getOutputStream());
dout.writeInt(files.length);
for (int i = 0; i < files.length; i++) {
dout.writeUTF(files[i].getName());
dout.flush();
dout.writeLong(files[i].length());
dout.flush();
totalSize += files[i].length();
}
dout.writeLong(totalSize);
for (int i = 0; i < files.length; i++) {
BufferedInputStream din = new BufferedInputStream(
new FileInputStream(files[i]));
while ((len = din.read(buf)) != -1) {
dout.write(buf, 0, len);
}
}
System.out.println("文件传输完毕");
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG,"send file exception");
}
return;
}
接收文件时有些复杂。每次从输入流中读入缓存中的数据有可能包括多个文件的内容,
须要利用每一个文件的大小信息把缓存中的数据放入不同的文件。
protected void receiveFile(Socket socket) {
File dirs = new File(mFilePath);
if (!dirs.exists()) {
dirs.mkdirs();
}
DataInputStream din = null;
int fileNum = 0;
long totalSize = 0;
FileInfo[] fileinfos = null;
try {
din = new DataInputStream(new BufferedInputStream(
socket.getInputStream()));
fileNum = din.readInt();
fileinfos = new FileInfo[fileNum];
for (int i = 0; i < fileNum; i++) {
fileinfos[i] = new FileInfo();
fileinfos[i].mFileName = din.readUTF();
fileinfos[i].mFileSize = din.readLong();
}
totalSize = din.readLong();
} catch (IOException e) {
e.printStackTrace();
Log.d(TAG,"readInt Exception");
System.exit(0);
}
System.out.println(fileNum);
System.out.println(totalSize);
for (FileInfo fileinfo : fileinfos) {
System.out.println(fileinfo.mFileName);
System.out.println(fileinfo.mFileSize);
}
// // /////////////////////////////////////////////////////////////////
int leftLen = 0; // 写满文件后缓存区中剩余的字节长度。
int bufferedLen = 0; // 当前缓冲区中的字节数
int writeLen = 0; // 每次向文件里写入的字节数
long writeLens = 0; // 当前已经向单个文件里写入的字节总数
long totalWriteLens = 0; // 写入的所有字节数
byte buf[] = new byte[8192];
for (int i = 0; i < fileNum; i++) {
writeLens = 0;
try {
FileOutputStream fout = new FileOutputStream(mFilePath
+ fileinfos[i].mFileName);
while (true) {
if (leftLen > 0) {
bufferedLen = leftLen;
} else {
bufferedLen = din.read(buf);
}
if (bufferedLen == -1)
return;
System.out.println("readlen" + bufferedLen);
// 假设已写入文件的字节数加上缓存区中的字节数已大于文件的大小,仅仅写入缓存区的部分内容。
if (writeLens + bufferedLen >= fileinfos[i].mFileSize) {
leftLen = (int) (writeLens + bufferedLen - fileinfos[i].mFileSize);
writeLen = bufferedLen - leftLen;
fout.write(buf, 0, writeLen); // 写入部分
totalWriteLens += writeLen;
move(buf, writeLen, leftLen);
break;
} else {
fout.write(buf, 0, bufferedLen); // 所有写入
writeLens += bufferedLen;
totalWriteLens += bufferedLen;
if (totalWriteLens >= totalSize) {
//mListener.report(GroupChatActivity.FAIL, null);
return;
}
leftLen = 0;
}
//mListener.report(GroupChatActivity.PROGRESS,
//(int) (totalWriteLens * 100 / totalSize));
} // end while
fout.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.d(TAG,"receive file Exception");
}
} // end for
//mListener.report(GroupChatActivity.FAIL, null);
}
注:在传输文件时还传输了文件的总大小,这样为了在接收文件时判定接收是否结束。
另一种传输方法比較复杂但更加灵活发送文件时依次传输每一个文件的名称。大小和内容。
相比上一个方法这样的发送方式接受时更难处理。
由于每次从输入流中读入缓存的数据可能包括了上一个文件的内容。下一个文件的名称和大小。
因为数据已被读入了缓存,这就不能利用DataInputStream的方法读取UTF字符串和Int,
必须从缓存中解析。
介绍两种解析方法
利用ByteArrayInputStream 把缓存中的内容转化为内存流然后利用DataInputStream读取。
手动解析,利用位运算拼接出Int。
注:Int 的长度为4是确定的。
WriteUTF 写入的字串长度存储在開始的两个字节中。
通过Socket连接一次传输多个文件的更多相关文章
- 对于.NET Socket连接的细节记录
如果客户端直接连接一个不存在的服务器端,客户端会抛出异常: 如果在连接过程中,客户端强制关闭了连接(没有调用Close直接关闭了程序),服务器端会抛出异常: 如果在连接过程中,客户端调用了Close, ...
- 比较 http连接 vs socket连接
http连接 :短连接,客户端,服务器三次握手建立连接,服务器响应返回信息,连接关闭,一次性的socket连接:长连接,客户端,服务器三次握手建立连接不中断(通过ip地址端口号定位进程)及时通讯,客户 ...
- UrlConnection连接和Socket连接的区别
关于UrlConnection连接和Socket连接的区别,只知道其中的原理如下: 抽象一点的说,Socket只是一个供上层调用的抽象接口,隐躲了传输层协议的细节. urlconnection 基于H ...
- 转 Cocos网络篇[3.2](3) ——Socket连接(1)
Cocos网络篇[3.2](3) ——Socket连接(1) 2015-03-05 22:24:13 标签:network http socket cocos [唠叨] 在客户端游戏开发中,使用HTT ...
- Http和Socket连接区别
相信不少初学手机联网开发的朋友都想知道Http与Socket连接究竟有什么区别,希望通过自己的浅显理解能对初学者有所帮助. 1.TCP连接 要想明白Socket连接,先要明白TCP连接.手机能够使用联 ...
- Http、tcp、Socket连接区别
转自Http.tcp.Socket连接区别 相信不少初学手机联网开发的朋友都想知道Http与Socket连接究竟有什么区别,希望通过自己的浅显理解能对初学者有所帮助. 1.TCP连接 要想明白Sock ...
- Socket连接与HTTP连接
我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP.FTP.T ...
- Http和Socket连接的区别
Http和Socket连接区别 相信不少初学手机联网开发的朋友都想知道Http与Socket连接究竟有什么区别,希望通过自己的浅显理解能对初学者有所帮助. 1.TCP连接 要想明白Socket连接,先 ...
- Http和Socket连接
转自http://hi.baidu.com/%D2%B9%D1%A9%B3%E6/blog/item/d6a72d2bbf467cf2e7cd406d.html 相信不少初学手机联网开发的朋友都想知道 ...
随机推荐
- KVM工具libvirt、virsh、virt-manager的简单介绍
KVM虚拟化中libvirt是目前使用最为广泛的对KVM虚拟机进行管理的工具和应用程序接口,而且一些常用的虚拟机管理工具(virsh.virt-install.virt-manager等)和云计算框架 ...
- Excel 电子表格文件格式剖析
Excel 电子表格文件格式,这种Excel和其他的Excel是不同的.他的本质上是一个Xml文件(用英文版的UtraEdit可以看到),所以他可以保存任何符号的字符,包括&(它在Xml文件中 ...
- 在Visual Studio中开发Matlab mex文件,生成mexw64/mexw32
csunking贡献,2015-9-22 1712 1. 概述 通过使用C/C++与Matlab混合编程,既可以享受到C代码快速执行的速度,又可以方便的使用Matlab众多的库函数和强大的绘图功能 ...
- Dreamweaver 支持Jquery智能提示
a.下载扩展插件:jQuery_API.mxp b.选择菜单栏:命令->扩展管理,选择刚下载的文件安装 c.重启DW 可以看到
- etcd,Docker问题汇总
单节点etcd publish error 正在愉快的进行jenkins流程,突然发现etcd连接不上去了.重新reboot后发现日志publish error Oct :: k8s-master e ...
- jQuery中,选择器既匹配开头又匹配结尾
jQuery中,选择器既匹配开头又匹配结尾的方法: [attr^=val]attr$=val [attr^=val][attr$=val]
- ECCV 2014 Oral Paper
今年的ECCV 的paper已经挂到了网上.本文整了当中Oral Paper. 一,Tracking and Activity Recognition
- HDU3001 Travelling 状压DP
哭瞎啊,每一个城市能够经过至多两次,但没有要求必须经过两次.想用 两个状压来乱搞搞.结果自觉得会T.结果 WA了,搞了一下午.没想到用三进制啊.智商捉急,參考了 http://blog.csdn.ne ...
- python 文件和路径操作函数小结
1: os.listdir(path) //path为目录 功能相当于在path目录下执行dir命令,返回为list类型 print os.listdir('..') 2: os.path.walk( ...
- linux中断流程详解
异常体系比较复杂,但是linux已经准备了很多的函数和框架,但是因为中断是和具体的开发板相关,所以中断需要我们自己来处理一些方面,但是这也是很少的一部分,很多公用的处理函数内核已经实现,linux内核 ...