java socket文件传输

    xiaoxiao2021-03-25  93

    注意点 :

    传输文件时,为了知道文件传输是否结束,可以在报头中添加文件长度或者文件末尾添加结束标志 - 特殊进制符号等.(个人感觉还是文件长度或者说是文件长度 + 结束标志,比较可靠)实际上的网络环境比较复杂,在公共网络的测试中,由于Server端网络较差,在传输过程中出现传输中断,有必要的情况下需要进行检查,避免出现无意义的等待和及时重新建立传输连接.

    下面是一个简单的socket实现文件传输.

    如果需要多个客户端接入,可以借助多线程,为每个连接创建一个线程去处理.

    如果需要双向传递,建议设计一个swing界面,目的是为将文件的发送和文件的接收界面分开,不管是dos或者控制台都不会满足你对双向的使用.

    Client.java

    import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.util.Date; /** * 数据组成 文件名 + 文件长度 + 文件内容 * @author pingguoliu * */ public class Client { public static void main(String[] args) throws IOException { String filePath; // 发送文件路径 File file; // 文件对象 FileInputStream fis = null; // 文件输入流 long fileLength = 0; // 文件长度 String fileName; // 文件名 String ip; // 服务器地址 InetAddress inetAddress; // ip封装对象 Socket socket = null; // 套接字 OutputStream os = null; // socket输出流对象 DataOutputStream dos = null; // 封装socket输出流 System.out.println("开始传输时间 : " + new Date()); filePath = "/Users/pingguoliu/Downloads/小兵传奇.txt"; // 需要发送的文件 // filePath = "/Users/pingguoliu/Downloads/斗破苍穹.dmg"; // filePath = "/Users/pingguoliu/Downloads/Hita -归路十里.mp4"; file = new File(filePath); fis = new FileInputStream(file); inetAddress = InetAddress.getLocalHost(); // 本机ip // ip = "60.176.38.204"; // 外网地址,两台不同主机 // inetAddress = InetAddress.getByName(ip); socket = new Socket(inetAddress, 9527); // 连接服务器 System.out.println("连接服务器成功,准备传输!"); os = socket.getOutputStream(); // 获得输出流对象 dos = new DataOutputStream(os); // 发送文件名、文件长度 fileName = file.getName(); // 获取文件名称 dos.writeUTF(fileName); // 发送文件名 System.out.println("文件名为 : " + fileName); fileLength = fis.available(); // 获取文件大小 dos.writeLong(fileLength); // 发送文件长度 System.out.println("文件长度为 : " + fileLength); int packLength = 0; // 数据包的长度 while(fileLength>0) { if (fileLength > 1024) { packLength = 1024; fileLength -= 1024; // # } else { packLength = (int)fileLength; fileLength = 0; } byte[] bytes = new byte[packLength]; fis.read(bytes, 0, packLength); // 读取数据 dos.write(bytes); // 填充数据 dos.flush(); } System.out.println("剩余文件长度 : " + fileLength); System.out.println("文件传输完毕!"); dos.close();// 输出流封装对象关闭 os.close(); // 输出流关闭 fis.close(); // 输入流关闭 socket.close(); // 与服务器连接关闭 } }

    Server.java

    import java.io.DataInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /** * 用于接受的传输文件的服务器 * @author pingguoliu * */ public class Server { public static void main(String[] args) throws IOException { ServerSocket server; // 服务器套接字 Socket socket; // 套接字 InputStream is; // 输入流 DataInputStream dis; // 封装输入流,具有方法 writeUTF、writeLong 可以方便传递文件名、文件长度 String filePath; // 文件输出位置 String fileName; // 文件名 long fileLength; // 文件长度 File file; // 文件对象 FileOutputStream fos; // 文件输出流 // 创建服务器,并等待客户端连接 server = new ServerSocket(9527); // 创建服务器套接字 System.out.println("服务器启动!"); socket = server.accept(); // 等待客户端连接 System.out.println("客户端连接成功!"); // 获取客户端连接 is = socket.getInputStream(); // 获取输入流 dis = new DataInputStream(is); // 封装输入流 // 获取文件名以及生成存放文件路径 //filePath = "C:/Users/薄幸何遇/Desktop/"; // 文件存放路径 fileName = dis.readUTF(); filePath += fileName; System.out.println("接受到的文件名 : " + fileName); file = new File(filePath); // 文件对象 if (!file.exists()) { file.createNewFile(); } fos = new FileOutputStream(file); // 获取文件输出流 // 获取文件大小 fileLength = dis.readLong(); System.out.println("接受到的文件大小 : " + fileLength); // 接收文件 receiveFile(fileLength, dis, fos); // receiveFile2(dis, fos); System.out.println("文件接收完毕!"); fos.close(); // 关闭输出流 is.close(); // 关闭输入流 socket.close(); // 关闭套接字 server.close(); // 关闭服务器 System.out.println("结束传输时间 : " + new Date()); } /** * 通过文件长度判断文件接受是否完成 * * @param fileLength * @param is * @param fos * @throws IOException */ private static void receiveFile(long fileLength, InputStream is, FileOutputStream fos) throws IOException { int bufferSize = 1024; // 缓冲区大小以及每次请求读入大小 int packLength = 0; // 单次获取的长度 /* * 存在空循环的问题,即读取到为0字节,fileLength长度>1024 * 虽然没有读取到文件长度,却将文件长度缩减 */ while(fileLength>0) { // 期望获取长度 if (fileLength > 1024) { packLength = 1024; //fileLength -= 1024; // #1 空循环代码 /* * 此时并不知道所读取本次读取的文件长度, * 由于网络的问题,所读取的长度可能并没有bufferSize大小, * * 导致存在文件长度的损失. */ } else { packLength = (int)fileLength; fileLength = 0; } byte[] bytes = new byte[bufferSize]; // 实际获取长度 packLength = is.read(bytes, 0, packLength); // 读取数据 System.out.println("packLength : " + packLength); if (packLength>0) { // #2 fileLength -= packLength; // 当读取数据不为0时,文件长度减少对应大小 } // fos.write(bytes); // 填充数据 /* * 由上可知存在bytes数组并不全满的情况,所以根据实际情况写入数据长度 * * 不然会出现虽然文件没有接收,但却出现文件大小并没有缺少的情况 */ fos.write(bytes, 0, packLength); } } /** * 直接根据是否能从输入流中读取字节作为判定. * @param is * @param fos * @throws IOException */ private static void receiveFile2(InputStream is, FileOutputStream fos) throws IOException { int bufferSize = 8192; int packLength = 0; // 单次获取的长度 byte[] bytes = new byte[bufferSize]; while((packLength = is.read(bytes))!= -1) { fos.write(bytes, 0, packLength); System.out.println("packLength :" + packLength); } /* * 上面文件传输结尾根据输出流的关闭. * 实际情况中很多时候,文件传输完成后连接并不关闭. */ } }

    由于网络环境,并不一定每次接受到你所期望的长度. 网络较差的时候,这张图上可能都是0.

    转载请注明原文地址: https://ju.6miu.com/read-35628.html

    最新回复(0)