写点什么

Java 高手速成 | 使用 TCP 进行手机文件传输

作者:TiAmo
  • 2023-02-07
    江苏
  • 本文字数:1763 字

    阅读完需:约 6 分钟

Java高手速成 | 使用TCP进行手机文件传输

由于 TCP 是面向流的,这意味着接收端有可能会在一次接收动作中接收两个或者多个数据包,那么当发送方需要把一个大文件分批连续发送时,如何保证接收方能够正确地接收并重修组会成一个完整的文件显得十分重要,本节通过一个端到端的手机文件传输程序,详细阐述了如何使用多线程进行任意大小文件的 TCP 分批发送和接收。


TCP 是面向流的。面向流是指无保护消息边界的,如果发送端连续发送数据,接收端有可能会在一次接收动作中接收两个或者更多的数据包。


举个例子来说,如果发送端连续发送三个数据包,大小分别是 1KB、2KB、4KB,这三个数据包都已经到达接收端缓冲区中,如果使用 UDP 协议,无论接收缓冲区多大,都必须有三次接收动作才能把所有数据包接收完。而使用 TCP 协议,只要把接收缓冲区大小设置为 7KB 以上,就能够一次将所有数据包接收下来,即只需进行一次接收动作。


这是由于 TCP 协议把数据当作一串数据流,所以并不知道消息的边界,即独立的消息之间是如何分隔开的。这便会造成消息的混乱,也就是说不能保证一个 Send 方法发出的数据被一个 Receive 方法读取。例如,客户端发送的消息是:第一次发送 abcde,第二次发送 12345,服务器方接收的可能是 abcde12345,即一次性接收完;也可能是第一次接收 abc,第二次接收 de123,第三次接收 45。


针对这个问题,一般有 3 种解决方案:①发送和接收定长的消息;②把消息的尺寸与消息一块发送;③使用特殊的标记来区分消息间隔。


下面通过一个具体的例子——手机文件传输,来说明如何使用上面方法解决接收方接收发送方连续发送的数据。


【例 1】编写基于 TCP 协议的手机文件传输程序。

本程序分为发送端程序 FileSend_TCP 与接收端程序 FileAccept_TCP。接收端使用后台服务来监听与接收文件,并将接收到的文件存储在 SD 卡中。发送端程序调用 Android 系统内置的相册,让用户选取图片文件,程序运行效果如图 1 所示。

先来看发送端程序 FileSend_TCP。发送端启用一个线程(SendThread)发送图片,为了帮助接收端对接收数据定界,数据组织为“文件名:文件长度:文件内容”。这样,接收方收到数据后可以根据“:”对各部分数据进行划分,通过文件长度对接收文件的内容定界。

FileSend_TCP 的 MainActivity.java:






程序中使用 sendRunnable 对象构造发送图像的线程,并在该线程中用 Toast 显示发送情况。由于 Toast.show()方法是将文本显示在界面上,故它需要通过消息队列来完成。Android 中使用 Looper 类封装消息队列,并为线程开启消息循环,默认情况下主线程会自动为其创建 Looper 对象,开启消息循环,但子线程是没有开启消息循环的。因此,在调用 Toast 的 show()方法前,需要使用 Looper.prepare()方法启用 Looper,在调用 Toast.show()方法后使用 Looper.loop(),使得上述操作能够在消息队列中被处理。


服务器端接收数据采用 Service 组件,Service 程序写在 ListenService.java 文件中,该服务启用一个监听线程(ListenThread)来监听客户端的连接,每当有连接进来则启用另一个接收线程(receiveThread)接收文件数据。

FileAccept_TCP 程序的 ListenService.java:








本示例同样要添加权限,两个程序还需添加对 SD 卡操作的权限。


最后,使分别运行 FileSend_TCP 和 FileAccept_TCP 程序的两个实体手机处于同一局域网中,在发送端 FileSend_TCP 程序界面的编辑框中输入接收端 FileAccept_TCP 的 IP 地址,从相册中选择图像后,就可以将图像发送到接收端的手机中了。

此外,本程序也可以在两个 Android 虚拟机中进行演示,如图 1 所示。首先开启两个虚拟机,让其中一个虚拟机,如 emulator-5554 运行接收端程序(服务器端),另一个虚拟机,emulator-5556 运行发送端程序(客户端)。然后,打开 Windows 的控制台程序,在其中输入如下命令。



■ 图 1 TCP 传输文件在两个 Android 9 虚拟机上的运行效果

其中,adb 是 android debug bridge,即 android 调试桥的缩写,它是 Android SDK 中的工具,监视 Socket TCP 5554 和其他端口,以允许集成开发环境和虚拟机进行通信,通过它可以直接操作和管理 Android 模拟器或实体机。上述命令会将发送到 TCP 端口 4567 上的数据重定向到接收端设备 emulator-5554 的 TCP 端口 4567 上,其格式为:


在 Android 虚拟机中,127.0.0.1 为虚拟机的地址,本地主机的地址映射为 10.0.2.2,因此,最后我们在 emulator-5556 虚拟机中输入 10.0.2.2,就可以通过上述重定向操作将发往本地主机 TCP 端口 4567 上的数据发送到 emulator-5554 设备的 TCP 端口 4567 上了。


发布于: 刚刚阅读数: 4
用户头像

TiAmo

关注

有能力爱自己,有余力爱别人! 2022-06-16 加入

CSDN全栈领域优质创作者;阿里云创作者社区专家博主、技术博主、星级博主、阿里云ACE;华为云享专家;

评论

发布
暂无评论
Java高手速成 | 使用TCP进行手机文件传输_Java_TiAmo_InfoQ写作社区