Java
day17_2023.8.31
序列化,反序列化
1,序列化:指的是,将Java对象转换为字节序列的过程,可以持久化存储到磁盘或者在网络上传输
2,反序列化:指的是,将字节序列再恢复成Java对象的过程
作用:在传递或者保存对象的时候,保证对象的完整性和可传递性
怎么实现序列化和反序列化?
序列化和反序列化的对象,要实现一个serializable接口
Serializable接口中没有任何方法需要实现类实现,主要的作用就是用来标识可序列化的语义
实现Serializable接口 的类,才可以被 ObjectInputStream和ObjectOutputStream识别,才可以被读取或者写出
public class Demo {
public static void main(String[] args) {
ObjectInputStream ois = null;
ObjectOutputStream ous = null;
try {
//序列化对象
ous = new ObjectOutputStream(new FileOutputStream("D:\\student.txt"));
//创建要被序列化的对象
Student s1 = new Student(1001, "jack", "1班");
System.out.println(s1);
//将对象序列化
ous.writeObject(s1);
//将对象反序列化
//反序列化对象
ois = new ObjectInputStream(new FileInputStream("D:\\student.txt"));
//反序列化返回的是Object对象,需要强转为Student
Object object = ois.readObject();
Student s2 = (Student) object;
System.out.println(s2);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if (ois != null){ois.close();}
if (ous != null){ ous.close();}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class Student implements Serializable {
private int sid;
private String name;
private String className;
public Student(int sid, String name, String className) {
this.sid = sid;
this.name = name;
this.className = className;
}
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", name='" + name + '\'' +
", className='" + className + '\'' +
'}';
}
}
通过IO流实现二进制文件的读写
/*
二进制文件的读写(文件复制)
*/
public class BinaryFileIO {
public static void main(String[] args) {
//DataInputStream DataOutputStream
FileInputStream fis = null;
DataInputStream dis =null;
FileOutputStream fos =null;
DataOutputStream dos =null;
try {
//创建文件输入流FileInputStream
fis = new FileInputStream("D:\\1.jpg");
//通过文件输入流创建 数据输入流DataInputStream
dis = new DataInputStream(fis);
//创建文件输入流FileInputStream
fos = new FileOutputStream("E:\\abc.jpg");
//通过文件输入流创建 数据输入流DataInputStream
dos = new DataOutputStream(fos);
int data;
//读的同时,将内容写出去
while ((data = dis.read()) != -1){
dos.write(data);
}
System.out.println("文件复制成功");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
dos.close();
fos.close();
dis.close();
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
计算机中的编码格式
在计算机中,任何文字都是以指定的编码方式存在的
Java中常见的编码格式 : ISO8859-1,GBK,UTF编码,Unicode
编码格式说明 :
ISO8859-1 : 属于单字节编码,最多只能标识0-255的字符范围
GBK: 中文的国标编码,用来标识汉字,属于双字节编码,可以用来标识简体字和繁体字
**UTF:**兼容了 ISO8859-1编码,同时又可以用来表示所有的语言字符,UTF是不定长编码,每个字符长度为1-6个字节不等,一般在中文网页使用此编码,可以节省空间,常用的一般是UTF-8
Unicode: 是一种编码规范,为了解决全球字符通用编码而设计的。UTF-8和UTF-16都是这个规范的一种实现,不兼容ISO8859-1 ,Java内部采用次编码规范
IO流中解决乱码问题:
public class BufferedReaderDemo {
public static void main(String[] args) {
try {
FileInputStream is = new FileInputStream("D:\\hello.txt");
//指定编码格式,格式跟文件的编码格式对应
InputStreamReader isr = new InputStreamReader(is, "GBK");
BufferedReader bufferedReader = new BufferedReader(isr);
String data ;
while ( (data = bufferedReader.readLine()) != null){
System.out.println(data);
}
//int data;
//while ( (data = is.read()) != -1){
// System.out.println((char) data);
//}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
网络编程
Java编写的程序,需要在网络上运行,Java程序也需要实现在网络上的数据连通。
Java中提供了一些网络相关的类库,可以让用户实现网络连接
Java实现了一个跨平台的网络库,程序员将来可以使用这种统一的编程环境完成网络连接功能
计算机网络
计算机网络指的是,通过通信线路,将地理位置不同的计算机连接起来,在操作系统、网络管理软件、网络通信协议的管理下,完成信息传递以及资源的共享
网络通信协议:
计算机网络中实现通信功能,必须要遵循的一些约定,就是通信协议
Java中的网络编程:
直接或者间接的通过网络通信协议,和其他计算机实现数据交互,进行通信
网络编程实现通信的关键点 :
1,如何准确的定位网络上的一台或者多台主机?
通过ip地址定位主机,通过端口号定位主机上的应用
2,找到主机后,怎么进行高效可靠的数据传输?
通过规定的传输协议 ,TCP/UDP协议
Java网络编程三要素
1,ip地址 : InetAddress
2,端口号
3,TCP/UDP协议
InetAddress类
此类表示Internet协议(IP)地址。IP地址是每台计算机在网络上的唯一标识地址
本地主机的IP地址 : 127.0.0.1 ,主机名 : localhost
IP地址分类 :
分类方式1:
IPV4和IPV6
IPV4:由4个字节,一共32位二进制数值组成, 4个 0-255范围的数值
IPV6:128位,16个字节,写成8个无符号整数,每个整数用4个16进制标识,数字之间用:隔开
分类方式2:
公网地址和私有地址, 192.168 开头的就是私有地址
public class IneAddressDemo {
public static void main(String[] args) throws UnknownHostException {
//1,直接通过主机名称,来获取主机IneAddress地址对象
InetAddress address1 = InetAddress.getByName("localhost");
System.out.println(address1);
InetAddress address2 = InetAddress.getByName("127.0.0.1");
System.out.println(address2);
//2,static InetAddress getLocalHost()
//返回本地主机的地址。 计算机名称 + ip地址
InetAddress address3 = InetAddress.getLocalHost();
System.out.println(address3);
//3,获取某个网站的地址
InetAddress address4 = InetAddress.getByName("www.baidu.com");
System.out.println(address4);
//其他方法的使用
System.out.println(address1.getAddress());
System.out.println(address1.getHostName());
System.out.println(address1.getHostAddress());
}
}
端口号的使用
端口用来表示计算机上运行的程序(具体的某个应用)
网络通信,本质上就是应用程序的通信,端口号,就是用来区分每个计算机上不同的应用程序的
端口号 :是一个16位的整数,0-65535的范围
TCP和UDP各有65535个端口,每个协议下的端口不能冲突
公认端口: 0-1023 被预先定义的服务器通信占用端口
常见端口 :
http: 80 https: 443 ftp: 21 telnet : 23 ssh : 22
注册端口 : 1024 - 49151 分配给用户进程或者应用程序的
常用的端口:
tomcat : 8080 mysql : 3306 oracle :1521
私有端口 : 49152 - 65535
netstat -ano 命令 用来查看端口
套接字对象Socket
ip地址和端口号组成的一个用来标识主机应用的类.
该类实现客户端套接字(也称为“套接字”)。 套接字是两台机器之间通讯的端点。
常用类
InetSocketAddress 该类实现IP套接字地址(IP地址+端口号)它也可以是一对(主机名+端口号)
public class SocketDemo {
public static void main(String[] args) throws IOException {
Socket socket =
new Socket(InetAddress.getByName("localhost"), 8080);
InetSocketAddress inetSocketAddress =
new InetSocketAddress("127.0.0.1", 8181);
}
}
通信协议
网络通信协议 :计算机网络中,遵循的一些约定,主要是对于 数据的传输速度、传输的代码、代码结构、传输控制步骤、错误信息控制等信息指定的一些标准
通信双方必须同时遵守这些约定才能完成数据交互
网络协议的实现方式 ?
通过将网络协议分层,每一个层,处理不同的事情,最终完成协议的约定
分层的内容 : 物理层、数据链路层、网络层、传输层、应用层
传输层的两个重要的协议 :
TCP(Transmission Control Protocol) : 传输控制协议
UDP(User Datagram Protocol) : 用户数据报协议
TCP协议
使用TCP协议之前,必须要建立TCP连接,形成传输数据通道
传输前,采用的 三次握手的方式,点对点建立连接,完成通信,是可靠的,安全的传输协议
在网络编程中,需要创建两个接口 : 客户端接口 、 服务端的接口
TCP可以进行大量的数据传输
传输完之后,需要释放建立的连接,效率相对较低一些
UDP协议
将数据、源、目的 封装成数据包,不需要建立连接
每个数据包大小限制在64kb以内
发送的时候,不去查看接收方是否准好,接收方收到后,也不会告诉发送方,收到数据
UDP是一种不可靠的传输
发送数据结束后,不需要释放资源,开销小,速度快
使用TCP完成数据传输
需求 :用户在客户端发送消息给服务端,服务端将数据展示在控制台上
/*
客户端
*/
public class TcpClient {
public static void main(String[] args) {
//使用tcp完成数据发送
//步骤:
OutputStream os = null;
Socket socket = null;
try {
//1,找到服务器,建立连接
//获取服务器地址对象,以及端口号
InetAddress serverIP = InetAddress.getByName("127.0.0.1");
//指定端口号,不要和本机上的端口号冲突了
int port = 8888;
//2,发送数据,通过ip+port 创建 Socket对象发送数据
socket = new Socket(serverIP, port);
//获取输出流outputStream
os = socket.getOutputStream();
os.write("你好,我是南邮的学生!".getBytes());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//3,关闭资源
try {
if (os != null){
os.close();
}
if (socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
服务端
*/
public class TcpServer {
public static void main(String[] args) {
ByteArrayOutputStream baos = null;
InputStream is = null;
Socket accept = null;
ServerSocket serverSocket = null;
//步骤:
//1,建立服务端的端口,创建ServerSocket对象
try {
serverSocket = new ServerSocket(8888);
//2,等待用户连接
while (true){
//侦听用户连接
accept = serverSocket.accept();
//3,接收用户消息
//获取输入流,读到数据
is = accept.getInputStream();
//使用ByteArrayOutputStream,将数据写出去
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int data;
while ((data = is.read(buffer)) != -1){
baos.write(buffer,0,data);
}
System.out.println(baos.toString());
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
baos.close();
is.close();
accept.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用TCP完成文件的上传,服务器收到上传文件,会返回一条信息给客户端,提示文件接收成功
/*
客户端
*/
public class TcpClient {
public static void main(String[] args) {
//使用tcp完成数据发送
//步骤:
OutputStream os = null;
Socket socket = null;
try {
//1,找到服务器,建立连接
//获取服务器地址对象,以及端口号
InetAddress serverIP =
InetAddress.getByName("127.0.0.1");
//指定端口号,不要和本机上的端口号冲突了
int port = 8888;
//2,发送数据,通过ip+port 创建 Socket对象发送数据
socket = new Socket(serverIP, port);
//获取输出流outputStream
os = socket.getOutputStream();
//获取上传的图文件对象
FileInputStream fis = new FileInputStream("D:\\1.jpg");
byte[] buffer = new byte[1024];
int data;
//完成图片的读取和写出
while ((data = fis.read(buffer)) != -1){
os.write(buffer,0,data);
}
//传输完之后,要关闭数据输出
socket.shutdownOutput();
//读取服务器返回的消息
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int data1;
while ((data1 = is.read(bytes)) != -1){
baos.write(bytes,0,data1);
}
System.out.println(baos.toString());
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
//3,关闭资源
try {
if (os != null){
os.close();
}
if (socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
服务端
*/
public class TcpServer {
public static void main(String[] args) {
InputStream is = null;
Socket accept = null;
ServerSocket serverSocket = null;
OutputStream os = null;
FileOutputStream fos = null;
//步骤:
//1,建立服务端的端口,创建ServerSocket对象
try {
serverSocket = new ServerSocket(8888);
//2,等待用户连接
//while (true){
//侦听用户连接
accept = serverSocket.accept();
//3,接收用户消息
//获取输入流,读到数据
is = accept.getInputStream();
//创建文件输出对象
fos = new FileOutputStream(new File("abc.jpg"));
byte[] buffer = new byte[1024];
int data;
while ((data = is.read(buffer)) != -1){
fos.write(buffer,0,data);
}
//通知客户端
os = accept.getOutputStream();
os.write("文件接收成功".getBytes());
//}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
os.close();
fos.close();
is.close();
accept.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
UDP实现数据传输
UDP传输需要封装一个数据包,Java中的数据包其实就是一个对象
DatagramPacket:该类表示数据报包。 数据包中,包含发送的 ip、端口、接收端的ip、端口、数据
DatagramSocket:此类表示用于发送和接收数据报数据包的套接字,UDP通过此类发送和接收数据
/*
UDP的客户端
*/
public class UdpClient {
public static void main(String[] args) throws IOException {
//1,创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket();
byte[] data = "你好,udp发送数据".getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
//2,封装数据包
DatagramPacket packet =
new DatagramPacket(data, 0, data.length, address, 9999);
//3,通过socket发送数据包
socket.send(packet);
socket.close();
}
}
/*
udp的接收方
*/
public class UdpServer {
public static void main(String[] args) throws IOException {
//建立DatagramSocket对象,并开放端口
DatagramSocket socket = new DatagramSocket(9999);
//接收数据
byte[] buffer = new byte[100];
//创建数据包,用来接收数据
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
//传入数据包接收数据
socket.receive(packet);
//把数据从包中取出,转为String
byte[] data = packet.getData();
String s = new String(data, 0, data.length);
System.out.println(s);
socket.close();
}
}
使用Udp实现一个模拟在线咨询的案例
用户可以输入一些信息,服务器接收到之后,根据用户输入的信息,作出自动的回应
/*
咨询方
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class ChatClient {
public static void main(String[] args) throws IOException {
System.out.println("已经接入咨询系统,可以发送消息了:");
//创建DatagramSocket对象,发送端的
DatagramSocket sendSocket = new DatagramSocket(8888);
//创建输入对象
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
//循环输入消息,实现发送多条消息
while (true){
String data = reader.readLine();
byte[] bytes = data.getBytes();
//放到数据包中
DatagramPacket packet = new DatagramPacket(bytes,0,bytes.length,new InetSocketAddress("localhost",6666));
sendSocket.send(packet);
// 创建接收数据包的对象
byte[] buffer = new byte[1024];
DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
// 接收服务器端的回复
sendSocket.receive(receivePacket);
// 提取回复内容并打印
String response = new String(receivePacket.getData(), 0, receivePacket.getLength());
System.out.println("收到回复: " + response);
//如果用户发送了byebye,那么就断开
if (data.equals("byebye")){
break;
}
}
}
}
/*
接收方
*/
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ChatServer {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(6666);
while (true){
//接收数据
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
socket.receive(packet);
//获取数据内容
byte[] data = packet.getData();
String s = new String(data,0,packet.getLength());
System.out.println("收到消息:" + s);
if (s.equals("你好")){
//数据返回
String response = "有什么需要帮助你的?";
byte[] responseData = response.getBytes();
DatagramPacket responsePacket = new DatagramPacket(responseData,responseData.length,packet.getSocketAddress());
socket.send(responsePacket);
System.out.println("发送回复:" + response);
}else if (s.equals("byebye")){
break;
} else{
String response = "对不起,我不明白您的意思";
byte[] responseData = response.getBytes();
DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length, packet.getSocketAddress());
socket.send(responsePacket);
System.out.println("发送回复:" + response);
}
}
}
}