基于Java实现Socket文件传输代码详解

文章目录

  • 前言
  • 一、Socket是什么?
  • 二、基于Socket的文件传输实战代码
    • 1.服务端代码
    • 2.客户端代码
  • 总结


前言

当涉及到网络通信和数据传输时,Socket 是一个非常重要的概念。Socket 可以被看作是在不同设备之间进行通信的一种方式,它提供了一种简单而强大的机制,用于实现客户端和服务器之间的数据交换。

在本博客中,我们将探讨 Socket 的基本原理和使用方法,并通过一个具体的示例来展示如何使用 Socket 进行文件传输。Socket 实战传输文件的代码将帮助你深入理解如何利用 Socket 在客户端和服务器之间传输文件。


一、Socket是什么?

Socket 是一种用于网络通信的编程接口,它提供了一种机制,使得不同设备之间可以进行数据的传输和交换。通过 Socket,我们可以在客户端和服务器之间建立起双向的通信连接。

在网络通信中,Socket 可以被看作是两个进程之间的一条管道或通道,它负责在不同设备之间传递数据。每个 Socket 都有一个唯一的标识,由 IP 地址和端口号组成,用于定位网络中的特定节点。

Socket 的工作原理基于 TCP/IP 协议栈。在建立通信之前,服务器需要绑定到一个特定的 IP 地址和端口号上,并监听来自客户端的连接请求。客户端则通过指定服务器的 IP 地址和端口号来发起连接。一旦连接建立,客户端和服务器就可以通过 Socket 进行数据的发送和接收。

通过 Socket,我们可以实现各种类型的网络应用,如聊天程序、文件传输、远程控制等。它提供了一种简单而强大的方式,使得不同设备之间能够进行高效、可靠的数据交换。

在 Java 中,使用 Socket 进行网络编程非常方便。Java 提供了 java.net 包中的 Socket 类,它封装了底层的网络通信细节,提供了一组方法来创建、连接和管理 Socket。通过 Socket 类,我们可以轻松地实现客户端和服务器之间的数据传输,并处理网络通信中可能出现的各种情况。

二、基于Socket的文件传输实战代码

1.服务端代码

public class SocketServerTest {

    private static final int SERVER_PORT = 9019; // 服务端端口
    private ServerSocket server;
    private Socket socket;
    private DataInputStream dis;
    private FileOutputStream fos;

    public SocketServerTest() throws Exception {
        server = new ServerSocket(SERVER_PORT);
    }

    public void task() throws IOException {
        Socket socket = server.accept(); // 等待客户端连接
        System.out.println("ip:" + socket.getInetAddress() + " 连接成功");
        try {
            dis = new DataInputStream(socket.getInputStream());
            // 读取文件名和长度
            String fileName = dis.readUTF();
            long fileLength = dis.readLong();

            File directory = new File("D:\\file");//要保存传输文件的绝对路径地址
            if (!directory.exists()) {
                directory.mkdir();
            }
            File file = new File(directory.getAbsolutePath() + File.separatorChar + fileName);
            file.createNewFile();
            fos = new FileOutputStream(file);
            System.out.println("fileName: " + fileName);
            System.out.println("======== 开始接收文件 ========");
            byte[] bytes = new byte[1024];
            int length = 0;
            while ((length = dis.read(bytes, 0, bytes.length)) != -1) {
                fos.write(bytes, 0, length);
                fos.flush();
            }

            System.out.println("======== 文件接收成功 ========");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null)
                    fos.close();
                if (dis != null)
                    dis.close();
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    public static void main(String[] args) {
        try {
            SocketServerTest server = new SocketServerTest(); // 启动服务端
            server.task();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这段代码是一个基于 Socket 的简单 Java 服务端实现,用于接收来自客户端的文件传输请求并保存文件到本地磁盘。下面对代码进行详细描述:

  • SocketServerTest 类是整个程序的入口点,它包含了 main 方法作为程序的起始位置。
  • 在类中定义了一些成员变量,包括 SERVER_PORT 常量,用于指定服务端监听的端口号;server、socket、dis、fos 分别代表服务器套接字、与客户端通信的套接字、与客户端交互的数据输入流和将文件写入磁盘的文件输出流。
  • 构造函数 SocketServerTest() 用于创建服务器套接字实例,并绑定到指定的端口。
  • task() 方法是主要处理逻辑,它通过调用 server.accept() 等待客户端连接,并在连接建立后开始接收文件数据。
  • 首先,代码显示等待连接的提示信息,并调用 server.accept() 方法来监听客户端的连接请求。一旦有客户端连接成功,将返回一个与该客户端通信的套接字对象。
  • 接下来,代码获取与客户端通信的输入流 dis,以便读取从客户端发送过来的文件名和文件长度。
  • 根据文件名,代码创建一个目录(如果目录不存在),然后通过 File 类构造函数创建一个新的文件对象。该文件对象表示要保存的文件,文件路径由目录路径和文件名组成。
  • 代码通过调用 file.createNewFile() 方法创建空文件,准备接收客户端传输的文件数据。
  • 创建文件输出流 fos,用于将接收到的数据写入磁盘文件中。
  • 接下来,代码显示开始接收文件的提示信息,并使用一个循环不断读取客户端发送的数据块,将其写入文件输出流中。
  • 当客户端发送的数据块长度为 -1(即无更多数据可读),循环结束,文件接收完成。
  • 最后,代码显示文件接收成功的提示信息,并在 finally 代码块中关闭打开的资源,包括文件输出流、数据输入流和套接字

2.客户端代码

public class SocketClientTest extends Socket {
    private  final String SERVER_IP="192.168.3.114";
    private final int SERVER_PORT=9019;
    private Socket client;
    private FileInputStream fis;
    private DataOutputStream dos;

    //创建客户端,并指定接收的服务端IP和端口号
    public SocketClientTest() throws IOException {
        this.client=new Socket(SERVER_IP,SERVER_PORT);
        System.out.println("成功连接服务端..."+SERVER_IP);
    }
    public void panduan(String path) throws IOException {
        File file = new File(path);
        if (file.isDirectory()) {
            String zipPath = zip(path);
            sendFile(zipPath);
        } else {
            sendFile(path);
        }
    }

    //向服务端传输文件
    public void sendFile(String url) throws IOException {
        File file=new File(url);
        try {
            fis = new FileInputStream(file);
            dos = new DataOutputStream(client.getOutputStream());//client.getOutputStream()返回此套接字的输出流
            //文件名、大小等属性
            dos.writeUTF(file.getName());
            dos.flush();
            dos.writeLong(file.length());
            dos.flush();
            // 开始传输文件
            System.out.println("======== 开始传输文件 ========");
            byte[] bytes = new byte[1024];
            int length = 0;

            while ((length = fis.read(bytes, 0, bytes.length)) != -1) {
                dos.write(bytes, 0, length);
                dos.flush();
            }
            System.out.println("======== 文件传输成功 ========");
        }catch(IOException e){
            e.printStackTrace();
            System.out.println("客户端文件传输异常");
        }finally{
            fis.close();
            dos.close();
        }
    }
    private static String zip(String url) throws IOException {
        File sourceFile = new File(url);
        String fileName = sourceFile.getName() + ".zip";
        String filepath = sourceFile.getParent() + File.separator + fileName;
        FileOutputStream fos = new FileOutputStream(filepath);
        ZipOutputStream zos = new ZipOutputStream(fos);
        zipFile(sourceFile, fileName, zos);
        zos.close();
        fos.close();
        System.out.println("文件/文件夹已压缩为:" + filepath);
        return filepath;
    }

    private static void zipFile(File fileToZip, String fileName, ZipOutputStream zos) throws IOException {
        if (fileToZip.isHidden()) {
            return;
        }
        if (fileToZip.isDirectory()) {
            if (fileName.endsWith("/")) {
                zos.putNextEntry(new ZipEntry(fileName));
            } else {
                zos.putNextEntry(new ZipEntry(fileName + "/"));
            }
            zos.closeEntry();
            File[] children = fileToZip.listFiles();
            if (children != null) {
                for (File childFile : children) {
                    zipFile(childFile, fileName + File.separator + childFile.getName(), zos);
                }
            }
            return;
        }
        FileInputStream fis = new FileInputStream(fileToZip);
        ZipEntry zipEntry = new ZipEntry(fileName);
        zos.putNextEntry(zipEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
            zos.write(bytes, 0, length);
        }
        fis.close();
    }
    public static void main(String[] args) {
        try {
            SocketClientTest client = new SocketClientTest(); // 启动客户端连接
            client.panduan("D:\\ajax_rmz"); // 要传输的文件绝对路径地址
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这段代码是一个基于 Socket 的简单 Java 客户端实现,用于向服务端发送文件。下面对代码进行详细描述:

  • SocketClientTest 类继承自 Socket 类,并包含了一些成员变量,包括 SERVER_IP 和 SERVER_PORT 常量,用于指定要连接的服务端的 IP 地址和端口号;client、fis、dos 分别代表客户端套接字、要传输的文件的输入流和与服务端交互的数据输出流。
  • 构造函数 SocketClientTest() 用于创建客户端套接字实例,并通过指定的服务端 IP 和端口号进行连接。
  • panduan(String path) 方法用于判断待发送的路径是文件还是目录。如果是目录,则将其压缩为一个 zip 文件后再进行发送;如果是文件,则直接发送该文件。
  • sendFile(String url) 方法用于向服务端传输文件。首先,代码根据文件路径创建一个 File 对象表示要传输的文件。然后,它打开文件的输入流 fis 和客户端套接字的输出流 dos,以便将文件数据写入到服务端。
  • 在向服务端传输文件之前,代码首先通过 dos.writeUTF(file.getName()) 将文件名发送给服务端,然后使用 dos.writeLong(file.length()) 发送文件大小信息。
  • 开始传输文件时,代码显示开始传输文件的提示信息,并通过一个循环读取文件数据块,并使用 dos.write(bytes, 0, length) 将数据写入到输出流中,从而发送给服务端。
  • 当文件数据读取完毕后,循环结束,代码显示文件传输成功的提示信息。
  • 在异常处理和最终关闭资源的部分,代码负责关闭文件输入流 fis 和数据输出流 dos。
  • 另外,代码还包含了两个私有静态方法 zip(String url) 和 zipFile(File fileToZip, String fileName, ZipOutputStream zos),用于将目录压缩为 zip 文件。这些方法实现了递归遍历目录,将目录下的所有文件和子目录进行压缩。

总结

在这篇博客中,我们学习了一个基于 Socket 的文件传输示例。代码包括服务端和客户端两部分。

服务端代码创建了一个 Socket 服务器,并监听指定的端口。一旦有客户端连接成功,服务端开始接收来自客户端的文件数据。它首先读取文件名和文件大小等属性,并创建一个同名的空文件。然后,通过循环逐块地接收并写入客户端发送的文件数据。最后,服务端输出文件接收成功的提示信息。

客户端代码创建了一个 Socket 客户端,并与指定的服务端进行连接。根据用户提供的路径,客户端判断是传输文件还是目录。如果是目录,客户端将压缩整个目录为一个 zip 文件后再进行传输;如果是文件,直接传输该文件。客户端通过套接字的输出流,将文件名和大小等信息发送给服务端,然后按块读取文件数据并发送给服务端。

通过这个示例,我们了解到使用 Socket 进行简单文件传输的基本原理。我们学会了建立客户端和服务端的连接,使用输入流和输出流进行数据传输,以及处理文件的读取、写入和目录的压缩。

希望大家可以通过本文深入了解Socket 这一技术,祝大家在使用Socket 时能取得成功!

你可能感兴趣的:(java,网络,websocket)