day20-网络编程
day20_网络编程
课程目标
1. 【理解】软件的架构
2. 【理解】网络通信协议
3. 【掌握】协议的分类
4. 【掌握】网络编程的三要素
5. 【掌握】InetAddress的使用
6. 【理解】UDP通信的使用
7. 【掌握】TCP发送数据和接收数据
8. 【掌握】综合案例
网络编程入门
软件结构
C/S结构
全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。
这种结构是将需要处理的业务合理地分配到客户端和服务器端,这样可以大大降低通信成本,但是升级维护相对困难。比如我们手机中安装的微信、qq、王者荣耀等应用程序就是C/S结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lA5NJWOa-1673765293962)(assets/1_cs.jpg)]
B/S结构
全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。
这种“B/S”结构有很多好处,维护和升级方式更简单,客户端是浏览器,基本不需要维护,只需要维护升级服务器端就可以
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9icQfZe0-1673765293963)(assets/2_bs.jpg)]
两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机的通信的程序。
网络通信协议
网络通信协议
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。
TCP/IP协议
传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。它定义了计算机如何连入因特网,以及数据如何在它们之间传输的标准。它的内部包含一系列的用于处理数据通信的协议,并采用了4层的分层模型,每一层都呼叫它的下一层所提供的协议来完成自己的需求。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-prCMC9nQ-1673765293966)(assets/3_tcp_ip.jpg)]
上图中,TCP/IP协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的通信功能。
链路层
:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。
网络层
:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。
传输层
:主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
应用层
:主要负责应用程序的协议,例如HTTP协议、FTP协议等。
协议的分类
通信的协议还是比较复杂的,
java.net
包中包含的类和接口,它们提供低层次的通信细节。我们可以直接使用这些类和接口,来专注于网络程序开发,而不用考虑通信的细节。
UDP
用户数据报协议(User Datagram Protocol)。UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。UDP的交换过程如下图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OVo09qtR-1673765293970)(assets/UDP通信图解.bmp)]
特点: 数据被限制在64kb以内,超出这个范围就不能发送了。
TCP
传输控制协议 (Transmission Control Protocol)。TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。
-
什么是三次握手
三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BNtRuq7X-1673765293974)(assets/4_tcp.jpg)]
完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛,例如下载文件、浏览网页等。
网络编程三要素
协议
计算机网络通信必须遵守的规则,已经介绍过了,不再赘述。
IP地址
IP地址:指互联网协议地址(Internet Protocol Address),俗称IP。IP地址用来给一个网络中的计算机设备做唯一的编号。假如我们把“个人电脑”比作“一台电话”的话,那么“IP地址”就相当于“电话号码”。
-
IP地址分类
-
【IPv4】:是一个32位的二进制数,通常被分为4个字节,表示成
a.b.c.d
的形式,例如192.168.65.100
。其中a、b、c、d都是0~255之间的十进制整数,那么最多可以表示42亿个。 -
【IPv6】:由于互联网的蓬勃发展,IP地址的需求量愈来愈大,但是网络地址资源有限,使得IP的分配越发紧张。
为了扩大地址空间,拟通过IPv6重新定义地址空间,采用128位地址长度,每16个字节一组,分成8组十六进制数,表示成
ABCD:EF01:2345:6789:ABCD:EF01:2345:6789
,号称可以为全世界的每一粒沙子编上一个网址,这样就解决了网络地址资源数量不够的问题。
-
-
常用命令
2端口号
网络的通信,本质上是两个进程(应用程序)的通信。每台计算机都有很多的进程,那么在网络通信时,如何区分这些进程呢?
如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的进程(应用程序)了。
- **端口号:用两个字节表示的整数,它的取值范围是065535**。其中,01023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
利用协议
+IP地址
+端口号
三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。
端口号
概念 : 程序(软件)在设备(电脑)中的唯一标识
端口号的取值范围
0~65535个端口, 前1024个端口号是系统保留端口号
常见服务占用的端口
80 : HTTP服务
http:// www.baidu.com:80
8080 : tomcat
3306 : mysql
1521 : oracle
443 : HTTPS服务, 安全加密的HTTP
21 : FTP服务, 文件传输
22 : SSH服务, 安全加密的远程登录
23 : Telnet服务, 远程登录
InetAddress
了解了IP地址的作用,我们看学习下JDK中提供了一个InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法,下表中列出了InetAddress类的一些常用方法。
常用方法
方法名 | 说明 |
---|---|
public static InetAddress getLocalHost() | 返回本地主机。 |
public static InetAddress getByName(String host) | 根据ip和主机名获取InetAddress |
public String getHostAddress() | 获取ip地址 |
public String getHostName() | 获取主机名 |
代码演示
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
// 获取[本地主机]InetAddress对象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost.getHostName());//DESKTOP-J1I3RQF
System.out.println(localHost.getHostAddress());//192.168.1.3
System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~");
// [根据主机名]获取InetAddress
InetAddress inetAddress = InetAddress.getByName("DESKTOP-J1I3RQF");
System.out.println(inetAddress);//DESKTOP-J1I3RQF/192.168.1.3
}
}
UDP通信程序
UDP发送数据
UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象,因此对于基于UDP协议的通信双方而言,没有所谓的客户端和服务器的概念
DatagramSocket类
Java提供了DatagramSocket类作为基于UDP协议的Socket
DatagramSocket构造方法
方法名 | 说明 |
---|---|
DatagramSocket() | 创建数据报套接字并将其绑定到本机地址上的任何可用端口 |
DatagramPacket(byte[] buf,int len,InetAddress add,int port) | 创建数据包,发送长度为len的数据包到指定主机的指定端口 |
DatagramSocket常用方法
方法名 | 说明 |
---|---|
void send(DatagramPacket p) | 发送数据报包 |
void close() | 关闭数据报套接字 |
void receive(DatagramPacket p) | 接受数据报包 |
DatagramSocket使用步骤
- 创建发送端的Socket对象(DatagramSocket)
- 创建数据,并把数据打包
- 调用DatagramSocket对象的方法发送数据
- 关闭发送端
DatagramSocket代码实现
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建发送端的Socket对象(DatagramSocket) 用于连接计算机的
//1、 DatagramSocket() 构造数据报套接字并将其绑定到本地主机上的任何可用端口
DatagramSocket ds = new DatagramSocket();
//创建数据,并把数据打包
//DatagramPacket(byte[] buf, int length, InetAddress address, int port)
//构造一个数据包,发送长度为 length的数据包到指定主机上的指定端口号。
byte[] bys = "hello,udp,我来了".getBytes();
//3、DatagramPacket这个类用于-数据打包
DatagramPacket dp = new DatagramPacket(bys,bys.length,InetAddress.getLocalHost(),10086);
//2、调用DatagramSocket对象的方法发送数据
//void send(DatagramPacket p) 从此套接字发送数据报包
ds.send(dp);
//4、关闭发送端
//void close() 关闭此数据报套接字
ds.close();
}
}
UDP接收数据
DatagramPacket类构造
方法名 | 说明 |
---|---|
DatagramPacket(byte[] buf, int len) | 创建一个DatagramPacket用于接收长度为len的数据包 |
DatagramPacket类方法
方法名 | 说明 |
---|---|
byte[] getData() | 返回数据缓冲区 |
int getLength() | 返回要发送的数据的长度或接收的数据的长度 |
接收数据的步骤
- 创建接收端的Socket对象(DatagramSocket)
- 创建一个数据包,用于接收数据
- 调用DatagramSocket对象的方法接收数据
- 解析数据包,并把数据在控制台显示
- 关闭接收端
接收数据代码实现
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//1、创建接收端的Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket(10086);
while (true) {
//3、创建一个数据包,用于接收数据
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
//2、调用DatagramSocket对象的方法-接收数据
ds.receive(dp);
//获取接收方的信息
System.out.println("发送方:"+dp.getAddress().getHostAddress() );
//解析数据包,把字节数据转成字符串输出
System.out.println("数据是:" + new String( dp.getData(), 0, dp.getLength()) );
}
}
}
实现聊天案例
/**
* @Desc 发送方
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建发送端的对象
DatagramSocket ds = new DatagramSocket();
//创建键盘对象
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请输入你要发送的内容:");
String s = sc.nextLine();
byte[] bytes = s.getBytes();
//DatagramPacket用于打包数据的
DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),10086);
//发送数据
ds.send(dp);
}
}
}
/**
* @Desc 接收方
*/
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//1、创建接收端
DatagramSocket ds = new DatagramSocket(10086);
while (true){
//创建一个数据包,用于接收数据
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
//获取发送方的信息
ds.receive(dp);
System.out.println(dp.getAddress().getHostAddress());
System.out.println(new String(dp.getData(), 0 , dp.getLength()));
}
}
}
TCP通信程序
TCP发送数据
Java对基于TCP协议的的网络提供了良好的封装,使用Socket对象来代表两端的通信端口,并通过Socket产生IO流来进行网络通信。
Socket类
Java为客户端提供了Socket类,用于创建客户端发送数据
Socket类构造
方法名 | 说明 |
---|---|
Socket(InetAddress address,int port) | 创建流套接字并将其连接到指定IP指定端口号 |
Socket(String host, int port) | 创建流套接字并将其连接到指定主机上的指定端口号 |
Socket类方法
方法名 | 说明 |
---|---|
InputStream getInputStream() | 返回此套接字的输入流 |
OutputStream getOutputStream() | 返回此套接字的输出流 |
代码实现
//客户端发送信息
public class ClientDemo {
public static void main(String[] args) throws IOException {
//获取当前主机ip
String hostAddress = InetAddress.getLocalHost().getHostAddress();
//创建发送方对象(客户端对象)创建流套接字并将其连接到指定主机上的指定端口号
Socket s = new Socket(hostAddress,10086);
//获取输出流写数据
OutputStream os = s.getOutputStream();
os.write("hello,tcp,我来了".getBytes());
//关闭资源
s.close();
//os.close(); 当客户端socket关闭,is流也关闭了
}
}
如果你只有客户端,没有服务端,单向会报连接失败错误
TCP接收数据
Java为服务器端提供了ServerSocket类,用于接收数据和处理数据
ServerSocket类构造
方法名 | 说明 |
---|---|
ServletSocket(int port) | 创建绑定到指定端口的服务器套接字 |
ServerSocket类方法
方法名 | 说明 |
---|---|
Socket accept() | 监听要连接到此的套接字并接受它 |
代码实现
//服务器端接收信息
public class ServerDemo {
public static void main(String[] args) throws IOException {
//1、创建服务器端的Socket对象(ServerSocket)
ServerSocket ss = new ServerSocket(10086);
//2、侦听要连接到此套接字并接受它
Socket socket = ss.accept();
//3、获取输入流,读数据
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println("发送方的ip:"+ InetAddress.getLocalHost().getHostAddress());//192.168.1.3
System.out.println("获取的数据是:"+new String(bytes,0,len));//hello,tcp,我来了
socket.close();
//is.close(); 当客户端socket关闭,is流也关闭了
//一般我只关闭客户端的socket,不关闭服务器的ServerSocket,服务器一关就接受不了任何数据了
//ss.close();
}
}
TCP通信程序回执
案例需求
客户端:发送数据,接受服务器反馈
服务器:收到消息后给出反馈
需求分析
- 客户端创建对象,使用输出流输出数据
- 服务端创建对象,使用输入流接受数据
- 服务端使用输出流给出反馈数据
- 客户端使用输入流接受反馈数据
代码实现
//服务端
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建服务器端的Socket对象(ServerSocket)
ServerSocket ss = new ServerSocket(10086);
//侦听要连接到此套接字并接受它
Socket socket = ss.accept();
//获取输入流,读数据
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
//【服务器 给 客户端反馈】
OutputStream os = socket.getOutputStream();
os.write("数据已经收到".getBytes());
System.out.println("发送方的ip:"+ InetAddress.getLocalHost().getHostAddress());
System.out.println("获取的数据是:"+new String(bytes,0,len));
socket.close();
}
}
//客户端
public class ClientDemo {
public static void main(String[] args) throws IOException {
//获取当前主机ip
String hostAddress = InetAddress.getLocalHost().getHostAddress();
//创建发送方对象(客户端对象)创建流套接字并将其连接到指定主机上的指定端口号
Socket s = new Socket(hostAddress,10086);
//获取输出流写数据
OutputStream os = s.getOutputStream();
os.write("hello,tcp,我来了".getBytes());
//【接收服务器反馈】读取服务器返回的信息
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
String data = new String(bys, 0, len);
System.out.println("客户端:" + data);
//关闭资源
s.close();
}
}
综合案例
文件上传案例
案例分析
- 【客户端】输入流,从硬盘读取文件数据到程序中。
- 【客户端】输出流,写出文件数据到服务端。
- 【服务端】输入流,读取文件数据到服务端程序。
- 【服务端】输出流,写出文件数据到服务器硬盘中。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mzs0NZD9-1673765293977)(assets/6_upload.jpg)]
代码实现
客户端实现
/**
* @Auther: yanqi
* @Desc 客户端:将本地文件读取并上传
*/
public class FileUPload_Client {
public static void main(String[] args) throws IOException {
//1、创建输入流,读取本地文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("一燕.jpg"));
//2、创建输出流,写到服务端
String hostAddress = InetAddress.getLocalHost().getHostAddress();
Socket socket = new Socket(hostAddress,10086);
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
//3、写出数据
byte[] bytes = new byte[1024*8];
int len;
while ( (len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
bos.flush();
}
System.out.println("文件发送完毕");
// 4、释放资源
bis.close();
bos.close();
socket.close();
System.out.println("文件上传完毕 ");
}
}
服务端实现
/**
* @Auther: yanqi
* @Desc 服务端:读出客户端的文件,把文件写到硬盘中
*/
public class FileUpload_Server {
public static void main(String[] args) throws IOException {
//1、创建服务端
ServerSocket serverSocket = new ServerSocket(10086);
//2、创建连接
Socket accept = serverSocket.accept();
//3、获取输入流,读出文件
BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("一燕2.jpg"));
//写数据
byte[] bytes = new byte[1024*8];
int len;
while ( (len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
}
//5. 关闭 资源
bos.close();
bis.close();
accept.close();
System.out.println("文件上传已保存");
}
}
信息回写
-
案例分析
前四步与基本文件上传一致.
- 【服务端】获取输出流,回写数据。
- 【客户端】获取输入流,解析回写数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f1wEtXYO-1673765293979)(assets/6_upload2.jpg)]
-
代码实现
-
服务端代码实现
/** * @Auther: yanqi * @Desc 服务端:读出客户端的文件,把文件写到硬盘中 */ public class FileUpload_Server { public static void main(String[] args) throws IOException { //1、创建服务端 ServerSocket serverSocket = new ServerSocket(10086); //2、创建连接 Socket accept = serverSocket.accept(); //3、获取输入流,读出文件 BufferedInputStream bis = new BufferedInputStream(accept.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("一燕2.jpg")); //4、写数据 byte[] bytes = new byte[1024*8]; int len; while ( (len = bis.read(bytes)) != -1){ bos.write(bytes,0,len); } //服务端 给 客户端反馈 OutputStream os = accept.getOutputStream(); os.write("回执信息:文件上传成功!".getBytes()); //5、关闭资源 bos.close(); bis.close(); accept.close(); System.out.println("文件上传已保存"); } }
-
客户端代码实现
/** * @Auther: yanqi * @Desc 客户端:将本地文件读取并上传 */ public class FileUPload_Client { public static void main(String[] args) throws IOException { //1、创建输入流,读取本地文件 BufferedInputStream bis = new BufferedInputStream(new FileInputStream("一燕.jpg")); //2、创建输出流,写到服务端 String hostAddress = InetAddress.getLocalHost().getHostAddress(); Socket socket = new Socket(hostAddress,10086); BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream()); //3、写出数据 byte[] bytes = new byte[1024*8]; int len; while ( (len = bis.read(bytes)) != -1){ bos.write(bytes,0,len); bos.flush(); } //5、注意:通知服务器,写出数据完毕 socket.shutdownOutput(); System.out.println("文件发送完毕"); // 5、[读出服务端的回写信息] InputStream is = socket.getInputStream(); int len2 = is.read(bytes); System.out.println(new String(bytes,0,len2)); is.close(); // 4、释放资源 bis.close(); socket.close(); System.out.println("文件上传完毕 "); } }
-
代码优化
-
循环接收的问题
【服务端】,指保存一个文件就关闭了,之后的用户无法再上传,这是不符合实际的,使用循环改进,可以不断的接收不同用户的文件
/** * @Auther: yanqi * @Desc 服务端:【模拟服务器一直处于开启状态,多个用户都可以上传文件】 */ public class FileUpload_Server { public static void main(String[] args) throws IOException { //1、创建服务端 ServerSocket serverSocket = new ServerSocket(10086); //【模拟服务器一直处于开启状态,多个用户都可以上传文件】 while (true){ //2、创建连接 Socket accept = serverSocket.accept(); //3、获取输入流,读出文件 BufferedInputStream bis = new BufferedInputStream(accept.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("一燕3.jpg")); //4、写数据 byte[] bytes = new byte[1024*8]; int len; while ( (len = bis.read(bytes)) != -1){ bos.write(bytes,0,len); } //服务端 给 客户端反馈 OutputStream os = accept.getOutputStream(); os.write("回执信息:文件上传成功!".getBytes()); //5、关闭资源 bos.close(); bis.close(); accept.close(); System.out.println("文件上传已保存"); }//end while } }
-
效率问题
【服务端,在接收大文件时,可能耗费几秒钟的时间,此时不能接收其他用户上传,所以,使用多线程技术优化
/** * @Auther: yanqi * @Desc 服务端:使用多线程模拟多个用户上传 */ public class FileUpload_Server { public static void main(String[] args) throws IOException { //1、创建服务端 ServerSocket serverSocket = new ServerSocket(10086); //【模拟服务器一直处于开启状态,多个用户都可以上传文件】 while (true){ //2、创建连接 Socket accept = serverSocket.accept(); //启动线程对象 new Thread(new UpLoadTread(accept)).start(); /* //3、获取输入流,读出文件 BufferedInputStream bis = new BufferedInputStream(accept.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.txt")); //4、写数据 byte[] bytes = new byte[1024*8]; int len; while ( (len = bis.read(bytes)) != -1){ bos.write(bytes,0,len); } //服务端 给 客户端反馈 OutputStream os = accept.getOutputStream(); os.write("回执信息:文件上传成功!".getBytes()); //5、关闭资源 bos.close(); bis.close(); accept.close(); System.out.println("文件上传已保存"); */ }//end while } }
public class UpLoadTread implements Runnable { private Socket accept; public UpLoadTread(Socket accept) { this.accept = accept; } @Override public void run() { try { //3、获取输入流,读出文件 BufferedInputStream bis = new BufferedInputStream(accept.getInputStream()); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("一燕3.jpg")); //4、写数据 byte[] bytes = new byte[1024*8]; int len; while ( (len = bis.read(bytes)) != -1){ bos.write(bytes,0,len); } //服务端 给 客户端反馈 OutputStream os = accept.getOutputStream(); os.write("回执信息:文件上传成功!".getBytes()); //5、关闭资源 bos.close(); bis.close(); accept.close(); System.out.println("文件上传已保存"); } catch (IOException e) { e.printStackTrace(); } } }
-
文件名称写死的问题
【服务端】,保存文件的名称如果写死,那么最终导致服务器硬盘,只会保留一个文件,建议使用系统时间优化,保证文件名称唯一
//BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("一燕3.jpg")); FileOutputStream fis = new FileOutputStream(System.currentTimeMillis()+".jpg") // 文件名称 BufferedOutputStream bos = new BufferedOutputStream(fis);
while ( (len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
}
//服务端 给 客户端反馈
OutputStream os = accept.getOutputStream();
os.write("回执信息:文件上传成功!".getBytes());
//5、关闭资源
bos.close();
bis.close();
accept.close();
System.out.println("文件上传已保存");
} catch (IOException e) {
e.printStackTrace();
}
}
}
* ##### 文件名称写死的问题
> 【服务端】,保存文件的名称如果写死,那么最终导致服务器硬盘,只会保留一个文件,建议使用系统时间优化,保证文件名称唯一
>
> ```java
> //BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("一燕3.jpg"));
> FileOutputStream fis = new FileOutputStream(System.currentTimeMillis()+".jpg") // 文件名称
> BufferedOutputStream bos = new BufferedOutputStream(fis);
> ```