iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java单个TCP连接发送多个文件的问题怎么解决
  • 801
分享到

Java单个TCP连接发送多个文件的问题怎么解决

2023-07-06 00:07:06 801人浏览 薄情痞子
摘要

这篇文章主要介绍“Java单个tcp连接发送多个文件的问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java单个TCP连接发送多个文件的问题怎么解决”文章能帮助大家解决问题。使用一个TC

这篇文章主要介绍“Java单个tcp连接发送多个文件的问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java单个TCP连接发送多个文件的问题怎么解决”文章能帮助大家解决问题。

    使用一个TCP连接发送多个文件

    为什么会有这篇博客? 最近在看一些相关方面的东西,简单的使用一下 Socket 进行编程是没有的问题的,但是这样只是建立了一些基本概念。对于真正的问题,还是无能为力。

    当我需要进行文件的传输时,我发现我好像只是发送过去了数据(二进制数据),但是关于文件的一些信息却丢失了(文件的扩展名)。而且每次我只能使用一个 Socket 发送一个文件,没有办法做到连续发送文件(因为我是依靠关闭流来完成发送文件的,也就是说我其实是不知道文件的长度,所以只能以一个 Socket 连接代表一个文件)。

    这些问题困扰了我好久,我去网上简单的查找了一下,没有发现什么现成的例子(可能没有找到吧),有人提了一下,可以自己定义协议进行发送。 这个倒是激发了我的兴趣,感觉像是明白了什么,因为我刚学过计算机网络这门课,老实说我学得不怎么样,但是计算机网络的概念我是学习到了。

    计算机网络这门课上,提到了很多协议,不知不觉中我也有了协议的概念。所以我找到了解决的办法:自己在 TCP 层上定义一个简单的协议。 通过定义协议,这样问题就迎刃而解了。

    协议的作用

    从主机1到主机2发送数据,从应用层的角度看,它们只能看到应用程序数据,但是我们通过图是可以看出来的,数据从主机1开始,每向下一层数据会加上一个首部,然后在网络上进行传播,当到达主机2后,每向上一层会去掉一个首部,达到应用层时,就只有数据了。(这里只是简单的说明一下,实际上这样还是不够严谨,但是对于简单的理解是够了。)

    Java单个TCP连接发送多个文件的问题怎么解决

    所以,我可以自己定义一个简单的协议,将一些必要的信息放在协议头部,然后让计算机程序自己解析协议头部信息,而且每一个协议报文就相当于一个文件。这样多个协议就是多个文件了。而且协议之间是可以区分的,不然的话,连续传输多个文件,如果无法区分属于每个文件的字节流,那么传输是毫无意义的。

    定义数据的发送格式(协议)

    这里的发送格式(我感觉和计算机网络中的协议有点像,也就称它为一个简单的协议吧)。

    发送格式:数据头+数据体

    数据头:一个长度为一字节的数据,表示的内容是文件的类型。 注:因为每个文件的类型是不一样的,而且长度也不相同,我们知道协议的头部一般是具有一个固定长度的(对于可变长的那些我们不考虑),所以我采用一个映射关系,即一个字节数字表示一个文件的类型。

    举一个例子,如下:

    keyvalue
    0txt
    1png
    2jpg
    3jpeg
    4avi

    注:这里我做的是一个模拟,所以我只要测试几种就行了。

    数据体: 文件的数据部分(二进制数据)。

    代码

    客户端

    协议头部类

    package com.draGon;public class Header {private byte type;      //文件类型private long length;      //文件长度public Header(byte type, long length) {super();this.type = type;this.length = length;}public byte getType() {return this.type;}public long getLength() {return this.length;}}

    发送文件类

    package com.dragon;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.net.Socket;public class FileTransfer {private byte[] header = new byte[9];   //协议的头部为9字节,第一个字节为文件类型,后面8个字节为文件的字节长度。public void transfer(Socket client, String src) throws FileNotFoundException, IOException {File srcFile = new File(src);File[] files = srcFile.listFiles(f->f.isFile());//获取输出流BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream());for (File file : files) {try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))){ //将文件写入流中String filename = file.getName();System.out.println(filename);//获取文件的扩展名String type = filename.substring(filename.lastIndexOf(".")+1);long len = file.length();//使用一个对象来保存文件的类型和长度信息,操作方便。Header h = new Header(this.getType(type), len);header = this.getHeader(h);//将文件基本信息作为头部写入流中bos.write(header, 0, header.length);//将文件数据作为数据部分写入流中int hasRead = 0;byte[] b = new byte[1024];while ((hasRead = bis.read(b)) != -1) {bos.write(b, 0, hasRead);}bos.flush();   //强制刷新,否则会出错!}}}private byte[] getHeader(Header h) {byte[] header = new byte[9];byte t = h.getType();  long v = h.getLength();header[0] = t;                  //版本号header[1] = (byte)(v >>> 56);   //长度header[2] = (byte)(v >>> 48);header[3] = (byte)(v >>> 40);header[4] = (byte)(v >>> 32);header[5] = (byte)(v >>> 24);header[6] = (byte)(v >>> 16);header[7] = (byte)(v >>>  8);header[8] = (byte)(v >>>  0);return header;}private byte getType(String type) {byte t = 0;switch (type.toLowerCase()) {case "txt": t = 0; break;case "png": t=1; break;case "jpg": t=2; break;case "jpeg": t=3; break;case "avi": t=4; break;}return t;}}

    注:

    1. 发送完一个文件后需要强制刷新一下。因为我是使用的缓冲流,我们知道为了提高发送的效率,并不是一有数据就发送,而是等待缓冲区满了以后再发送,因为 IO 过程是很慢的(相较于 CPU),所以如果不刷新的话,当数据量特别小的文件时,可能会导致服务器端接收不到数据(这个问题,感兴趣的可以去了解一下。),这是一个需要注意的问题。(我测试的例子有一个文本文件只有31字节)。

    2. getLong() 方法将一个 long 型数据转为 byte 型数据,我们知道 long 占8个字节,但是这个方法是我从Java源码里面抄过来的,有一个类叫做 DataOutputStream,它有一个方法是 writeLong(),它的底层实现就是将 long 转为 byte,所以我直接借鉴过来了。(其实,这个也不是很复杂,它只是涉及了位运算,但是写出来这个代码就是很厉害了,所以我选择直接使用这段代码,如果对于位运算感兴趣,可以参考一个我的博客:位运算)。

    测试类

    package com.dragon;import java.io.IOException;import java.net.Socket;import java.net.UnknownHostException;//类型使用代号:固定长度//文件长度:long->byte 固定长度public class Test {public static void main(String[] args) throws UnknownHostException, IOException {FileTransfer fileTransfer = new FileTransfer();try (Socket client = new Socket("127.0.0.1", 8000)) {fileTransfer.transfer(client, "D:/DBC/src");}}}
    服务器

    协议解析类

    package com.dragon;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.net.Socket;import java.util.UUID;public class FileResolve {private byte[] header = new byte[9];  public void fileResolve(Socket client, String des) throws IOException {BufferedInputStream bis = new BufferedInputStream(client.getInputStream());File desFile = new File(des);if (!desFile.exists()) {if (!desFile.mkdirs()) {throw new FileNotFoundException("无法创建输出路径");}}while (true) {//先读取文件的头部信息int exit = bis.read(header, 0, header.length);//当最后一个文件发送完,客户端会停止,服务器端读取完数据后,就应该关闭了,//否则就会造成死循环,并且会批量产生最后一个文件,但是没有任何数据。if (exit == -1) {System.out.println("文件上传结束!");break;   }String type = this.getType(header[0]);String filename  = UUID.randomUUID().toString()+"."+type;System.out.println(filename);//获取文件的长度long len = this.getLength(header);long count = 0L;try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(des, filename)))){int hasRead = 0;byte[] b = new byte[1024];while (count < len && (hasRead = bis.read(b)) != -1) {bos.write(b, 0, hasRead);count += (long)hasRead;int last = (int)(len-count);if (last < 1024 && last > 0) {//这里不考虑网络原因造成的无法读取准确的字节数,暂且认为网络是正常的。byte[] lastData = new byte[last];bis.read(lastData);bos.write(lastData, 0, last);count += (long)last;}}}}}private String getType(int type) {String t = "";switch (type) {case 0: t = "txt"; break;case 1: t = "png"; break;case 2: t = "jpg"; break;case 3: t = "jpeg"; break;case 4: t = "avi"; break;}return t;}private long getLength(byte[] h) {return (((long)h[1] << 56) +                ((long)(h[2] & 255) << 48) +                ((long)(h[3] & 255) << 40) +                ((long)(h[4] & 255) << 32) +                ((long)(h[5] & 255) << 24) +                ((h[6] & 255) << 16) +                ((h[7] & 255) <<  8) +                ((h[8] & 255) <<  0));}}

    注:

    1. 这个将 byte 转为 long 的方法,相信大家也能猜出来了。DataInputStream 有一个方法叫 readLong(),所以我直接拿来使用了。(我觉得这两段代码写的非常好,不过我就看了几个类的源码,哈哈!)

    2. 这里我使用一个死循环进行文件的读取,但是我在测试的时候,发现了一个问题很难解决:什么时候结束循环。 我一开始使用 client 关闭作为退出条件,但是发现无法起作用。后来发现,对于网络流来说,如果读取到 -1 说明对面的输入流已经关闭了,因此使用这个作为退出循环的标志。如果删去了这句代码,程序会无法自动终止,并且会一直产生最后一个读取的文件,但是由于无法读取到数据,所以文件都是 0 字节的文件。 (这个东西产生文件的速度很快,大概几秒钟就会产生几千个文件,如果感兴趣,可以尝试一下,但是最好快速终止程序的运行,哈哈!

    if (exit == -1) {System.out.println("文件上传结束!");break;   }

    测试类

    这里只测试一个连接就行了,这只是一个说明的例子。

    package com.dragon;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;public class Test {public static void main(String[] args) throws IOException {try (ServerSocket server = new ServerSocket(8000)){Socket client = server.accept();FileResolve fileResolve = new FileResolve();fileResolve.fileResolve(client, "D:/DBC/des");}}}

    测试结果

    Client

    Java单个TCP连接发送多个文件的问题怎么解决

    Server

    Java单个TCP连接发送多个文件的问题怎么解决

    源文件目录 这里面包含了我测试的五种文件。注意对比文件的大小信息,对于IO的测试,我喜欢使用图片和视频测试,因为它们是很特殊的文件,如果错了一点(字节少了、多了),文件基本上就损坏了,表现为图片不正常显示,视频无法正常播放。

    Java单个TCP连接发送多个文件的问题怎么解决

    目的文件目录

    Java单个TCP连接发送多个文件的问题怎么解决

    关于“Java单个TCP连接发送多个文件的问题怎么解决”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

    --结束END--

    本文标题: Java单个TCP连接发送多个文件的问题怎么解决

    本文链接: https://www.lsjlt.com/news/356808.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • Java单个TCP连接发送多个文件的问题怎么解决
      这篇文章主要介绍“Java单个TCP连接发送多个文件的问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java单个TCP连接发送多个文件的问题怎么解决”文章能帮助大家解决问题。使用一个TC...
      99+
      2023-07-06
    • 关于Java单个TCP(Socket)连接发送多个文件的问题
      目录使用一个TCP连接发送多个文件协议的作用定义数据的发送格式(协议)代码客户端服务器端测试结果总结使用一个TCP连接发送多个文件 为什么会有这篇博客? 最近在看一些相关方面的东西,...
      99+
      2023-05-15
      Java单个(Socket)TCP Java TCP发送多个文件
    • 多个服务连接redis并发问题如何解决
      解决多个服务连接Redis并发问题可以通过以下几种方法:1. 连接池:使用连接池来管理多个连接,每个服务从连接池中获取一个连接,使用...
      99+
      2023-09-04
      redis
    • vue如何解决一个方法同时发送多个请求的问题
      这篇文章主要介绍了vue如何解决一个方法同时发送多个请求的问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。在...
      99+
      2024-04-02
    • redis无法多个连接怎么解决
      如果Redis无法建立多个连接,可能是因为配置问题或者服务器资源不足导致的。以下是一些可能的解决方法:1. 检查Redis配置文件:...
      99+
      2023-09-01
      redis
    • Java怎么解决接口并发问题
      在Java中,可以通过以下几种方法来解决接口并发问题:1. 同步方法:可以在接口的实现类中使用synchronized关键字来修饰方...
      99+
      2023-09-12
      Java
    • PHP mail发送邮件出现问题怎么解决
      这篇文章主要介绍“PHP mail发送邮件出现问题怎么解决”,在日常操作中,相信很多人在PHP mail发送邮件出现问题怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PHP mail发送邮件出现问题怎...
      99+
      2023-06-17
    • python多线程请求带参数的多个接口问题怎么解决
      这篇文章主要介绍了python多线程请求带参数的多个接口问题怎么解决的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python多线程请求带参数的多个接口问题怎么解决文章都会有所收获,下面我们一起来看看吧。多线程...
      99+
      2023-07-05
    • axios发送post请求上传文件到后端的问题怎么解决
      这篇“axios发送post请求上传文件到后端的问题怎么解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“axios发送po...
      99+
      2023-06-30
    • tomcat怎么访问多个磁盘的文件
      要让Tomcat访问多个磁盘的文件,可以按照以下步骤进行操作: 打开Tomcat的配置文件server.xml,该文件位于Tom...
      99+
      2024-02-29
      tomcat
    • 如何解决Weblogic只允许能连接5个IP的问题
      这篇文章主要讲解了“如何解决Weblogic只允许能连接5个IP的问题”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何解决Weblogic只允许能连接5个IP的问题”吧!0. Weblog...
      99+
      2023-06-03
    • java多线程写文件出现冲突问题怎么解决
      在多线程写文件时,可能会出现冲突问题,可以通过以下几种方式解决: 使用锁(Lock):在文件写入操作之前,先获取一个锁,其他线程...
      99+
      2024-02-29
      java
    • 如何解决jsp中的rar文件连接乱码问题
      这篇文章主要讲解了“如何解决jsp中的rar文件连接乱码问题”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何解决jsp中的rar文件连接乱码问题”吧!在jsp页面中做了一个rar文件的链接...
      99+
      2023-06-03
    • 怎么解决mysql连接过慢的问题
      这篇文章主要讲解了“怎么解决mysql连接过慢的问题”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么解决mysql连接过慢的问题”吧! 3种解决方法(前...
      99+
      2024-04-02
    • 如何解决axios会发送两次请求有个OPTIONS请求的问题
      这篇文章主要为大家展示了“如何解决axios会发送两次请求有个OPTIONS请求的问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何解决axios会发送两次...
      99+
      2024-04-02
    • C#函数out多个返回值问题怎么解决
      今天小编给大家分享一下C#函数out多个返回值问题怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。C#函数返回多个参数...
      99+
      2023-07-05
    • mysql多个客户端连接出现错误怎么解决
      当出现多个客户端连接mysql数据库时出现错误,通常是由于数据库连接数限制引起的。解决方法如下: 增加连接数限制:可以通过修改m...
      99+
      2024-04-09
      mysql
    • 如何解决mysql多个字段update时错误使用and连接字段的问题
      这篇文章主要介绍了如何解决mysql多个字段update时错误使用and连接字段的问题,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下...
      99+
      2024-04-02
    • Java中properties文件编码问题怎么解决
      本文小编为大家详细介绍“Java中properties文件编码问题怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“Java中properties文件编码问题怎么解决”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知...
      99+
      2023-06-29
    • java读写ini文件、FileOutputStream问题怎么解决
      这篇文章主要介绍“java读写ini文件、FileOutputStream问题怎么解决”,在日常操作中,相信很多人在java读写ini文件、FileOutputStream问题怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作...
      99+
      2023-07-06
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作