基于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 时能取得成功!