通过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连接一次传输多个文件

时间: 2024-10-30 14:00:57

通过Socket连接一次传输多个文件的相关文章

socket连接和TCP连接的关系

我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP.FTP.TELNET等,也可以自己定义应用层协议.WEB使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将它发到网络上. 1)Socket是一个针对TCP和UDP编程的接口,你可以借助它建立TCP连接等等.而TCP和UDP协议属于传输层 . 而http是个应用层的协议,它

Http和Socket连接区别

1.TCP连接 要想明白Socket连接,先要明白TCP连接.手机能够使用联网功能是因为手机底层实现了TCP/IP协议,可以使手机终端通过无线网络建立TCP连接.TCP协议可以对上层网络提供接口,使上层网络数据的传输建立在“无差别”的网络之上. 建立起一个TCP连接需要经过“三次握手”: 第一次握手:客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k

Android 通过局域网udp广播自动建立socket连接

Android开发中经常会用到socket通讯.由于项目需要,最近研究了一下这方面的知识. 需求是想通过wifi实现android移动设备和android平台的电视之间的文件传输与控制. 毫无疑问这中间一定需要用到socket来进行通信.今天就两台设备的握手连接方式分享一下吧,该方法只是本人个人想法的实现,仅供参考,如有雷同,不胜荣幸. 要想使用socket进行通讯,就必须知道服务端的IP地址,我使用的是通过udp局网广播来实现局网内服务端的搜寻建立连接.以下是代码实现. 首先是客户端: pub

android 使用Ntrip协议,socket连接获取接入点,登录模式

前段时间出差去解决一个问题,就是获取接入点,还有登录模式.手机网络差分设置的问题,在这过程是使用Ntrip协议的.这个有点坑的地方,是在于服务器那边是不是按照协议来标准处理这些验证数据.首先是一个socket连接,socket连接上了发送协议.这个协议就是Ntrip来做的. Ntrip协议的下载地址:点击 1.使用背景 使用最多就是手机卡的接入点设置,android 系统设置,移动网络,可以新建apn设置.有些专卡,专网使用需要自已设置apn.平时我们自已使用的手机网络的接入点都是默认的.如下图

socket连接和HTTP连接的区别

简单说, 你浏览的网页(网址以HTTP:// 开头) 都是HTTP协议传输到你的浏览器的, 而HTTP是基于socket之上的, socket是一套完成TCP, UDP协议的接口. HTTP协议: 简单对象访问协议, 对应于应用层, HTTP协议是基于TCP连接的. TCP协议: 对应于传输层 IP协议: 对应于网络层 TCP/IP是传输层协议, 主要解决数据如何在网络中传输: 而HTTP是应用层协议, 主要解决如何包装数据. socket是对TCP/IP协议的封装, socket本身并不是协议

UrlConnection连接和Socket连接的区别

关于UrlConnection连接和Socket连接的区别,只知道其中的原理如下:抽象一点的说,Socket只是一个供上层调用的抽象接口,隐躲了传输层协议的细节.urlconnection 基于Http协议,Http协议是应用层协议,对传输层Tcp协议进行了封装,是无状态协议,不需要你往考虑线程.同步.状态治理等,内部是通过socket进行连接和收发数据的,不过一般在数据传输完成之后需要封闭socket连接.直接使用Socket进行网络通讯得考虑线程治理.客户状态监控等,但是不用发送头信息等,更

Cocos网络篇[3.2](3) ——Socket连接(1)

[唠叨] 在客户端游戏开发中,使用HTTP进行网络通信的比较少,一般使用的都是Socket进行通信.而HTTP一般用于网页或者网页游戏. 使用第三方Socket通信库:ODSocket. [参考] http://blog.csdn.net/sight_/article/details/8138802 (Socket详解) http://blog.csdn.net/hguisu/article/details/7444092 (Socket编程原理) [源码下载] ODSocket库源码:http

Android连接socket服务器上传下载多个文件

android连接socket服务器上传下载多个文件1.socket服务端SocketServer.java public class SocketServer { int port = 8888;// 端口号,必须与客户端一致 // 选择进行传输的文件(测试) String path = "C:\\Temp"; String filePath = "E:\\img.png"; Socket client; public static void main(Strin

TCP连接的三次握手,TCP/UDP区别联系,socket连接和http连接的区别

TCP连接的三次握手 1.第一次握手:客户端发送SYN + J包(syn = j)到服务器,并进入SYN_SEND状态,等待服务器确认: 2.第二次握手:服务器收到syn包,必须确认客户的SYN(A出口= j+1),同时自己也发送一个SYN+K包(syn =k),即SYN +ACK包,向服务器发送确认包ACK(ack = k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手, TCP/UDP区别联系 1.TCP的全称是传输控制协议,这种协议可以提供面向连接的,可靠地