1.案例需求
使用字节流从客户端发送视频文件到服务端,服务端通知客户端文件上传完毕
2.编程思路
- 客户端
- 打开视频文件:使用FileInputStream打开要发送的视频文件。
- 建立网络连接:创建一个Socket对象,连接到服务端的指定IP地址和端口。
- 发送文件数据:将FileInputStream包装在BufferedInputStream中以提高效率。
- 读取视频文件的内容,并通过Socket的getOutputStream()方法写入到网络流中。可以使用一个循环来持续读取文件内容,直到文件末尾(即read()方法返回-1)。
- 等待服务端响应:发送完文件后,客户端可以通过Socket的getInputStream()读取服务端的响应,确认文件是否接收成功。
- 关闭资源:关闭FileInputStream、BufferedInputStream和Socket,释放资源。
- 服务端
- 监听网络连接:使用ServerSocket在指定端口上监听客户端的连接请求。
- 接受客户端连接:当客户端连接时,ServerSocket的accept()方法会返回一个Socket对象,用于与客户端通信。
- 接收文件数据:通过Socket的getInputStream()获取输入流,并将其包装在BufferedInputStream中以提高读取效率。创建一个FileOutputStream用于将接收到的数据写入到本地文件系统中。读取输入流中的数据,并写入到FileOutputStream中,直到输入流结束。
- 文件接收完毕处理:当文件接收完毕后,可以执行一些后处理操作,如校验文件完整性等。
- 通知客户端:通过Socket的getOutputStream()发送一个确认消息给客户端,表明文件已成功接收。这个消息可以是一个简单的字符串,如"服务端文件接收成功"。
- 关闭资源:关闭Socket、FileInputStream(如果有的话,实际上在服务端这里应该是FileOutputStream)、和任何其他打开的流资源。
3.案例源码
服务端源码:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Serve {
public static void main(String[] args) throws IOException {
ServerSocket serve = new ServerSocket(7835);
System.out.println("服务器已开启,等待连接...");
Socket client = serve.accept();
System.out.println("客户端:" + client.getInetAddress() + "已连接");
BufferedInputStream bisSocket = new BufferedInputStream(client.getInputStream());
BufferedOutputStream bosVideo = new BufferedOutputStream(new FileOutputStream("D:/hh.mp4"));
BufferedOutputStream bos = new BufferedOutputStream(client.getOutputStream());
int len;
byte[] bytes = new byte[1024 * 1024];
while ((len = bisSocket.read(bytes)) != -1) {
bosVideo.write(bytes, 0, len);
bosVideo.flush();
}
System.out.println("服务端接受视频完毕");
client.shutdownInput();
String str = "服务端接受视频完毕!";
bos.write(str.getBytes());
bos.flush();
client.shutdownOutput();
bos.close();
bosVideo.close();
bisSocket.close();
client.close();
serve.close();
}
}
客户端源码:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket client = new Socket("localhost", 7835);
System.out.println("客服端已启动...");
// 上传
BufferedInputStream bisVideo = new BufferedInputStream(new FileInputStream("C:/hh.mp4"));
BufferedOutputStream bosScoket = new BufferedOutputStream(client.getOutputStream());
BufferedInputStream bis = new BufferedInputStream(client.getInputStream());
int len;
byte[] bytes = new byte[1024 * 1024];
while ((len = bisVideo.read(bytes)) != -1) {
bosScoket.write(bytes, 0, len);
bosScoket.flush();
}
System.out.println("客户端视频上传完毕!");
client.shutdownOutput();
byte[] bytes1 = new byte[1024];
String msg = "";
while ((len = bis.read(bytes1)) != -1) {
String s = new String(bytes1, 0, len);
msg+=s;
}
System.out.println("服务器说:" + msg);
client.shutdownInput();
bis.close();
bosScoket.close();
bisVideo.close();
client.close();
}
}
4.小结
- 网络编程基础
- Socket 编程
- Socket:是网络编程中的基本概念,代表了一个连接的一端。它提供了端到端的通信能力,使得不同机器上的程序可以进行数据交换。
- TCP/IP:Socket 编程通常基于TCP/IP协议,这是一种可靠的、面向连接的、基于字节流的传输层通信协议。
- ServerSocket
- 监听端口:ServerSocket 在服务器端创建,用于监听来自客户端的连接请求。它绑定到一个特定的端口上,等待客户端的连接。
- accept 方法:当客户端发起连接请求时,ServerSocket 的 accept 方法会被调用,并返回一个 Socket 对象,该对象代表了与客户端的连接。
- Socket(客户端)
- 连接到服务器:客户端通过创建 Socket 对象并指定服务器的IP地址和端口来连接到服务器。
- 输入输出流:一旦连接建立,客户端就可以通过 Socket 对象的 getInputStream 和 getOutputStream 方法获取输入和输出流,用于与服务器进行数据交换。
- 字节流
- 字节流概述
- 二进制数据:字节流用于处理二进制数据,如图片、视频文件等。它们以字节为单位进行数据的读写。
- FileInputStream 和 FileOutputStream
- 文件读取:FileInputStream 用于从文件中读取数据。它提供了一系列方法,如 read,用于从文件中读取字节。
- 文件写入:FileOutputStream 用于向文件中写入数据。它同样提供了一系列方法,如 write,用于将字节写入文件。
- BufferedInputStream 和 BufferedOutputStream
- 缓冲机制:为了提高数据读写效率,BufferedInputStream 和 BufferedOutputStream 提供了带缓冲区的字节流。它们通过内部缓冲区来减少实际读写操作的次数。
- 异常处理
- IOException:是处理输入输出操作时可能抛出的异常。它涵盖了几乎所有与IO操作相关的错误情况,如文件不存在、磁盘空间不足、网络中断等。
- try-catch-finally:用于捕获和处理异常,并确保资源被正确关闭。在 try 块中执行可能抛出异常的代码,在 catch 块中处理异常,在 finally 块中执行清理代码(如关闭文件和网络流)。
- 文件处理
- 文件路径和名称:在读写文件时,需要指定文件的完整路径和名称。这可以是绝对路径,也可以是相对路径。
- 文件权限:程序需要有足够的权限来读取源文件并写入目标文件。如果权限不足,将会抛出 SecurityException 或 IOException。
- 资源管理
- 关闭资源:使用完文件、网络流等资源后,应及时关闭以释放系统资源。在Java中,可以使用 try-with-resources 语句来自动管理资源,它确保了即使在发生异常的情况下,资源也能被正确关闭。