文章目录
网络编程
软件结构
C/S架构:全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。用户体验效果好,对信息的安全控制较强,应用服务器运行数据负荷较轻,部分计算在客户端完成。
B/S结构:全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。维护方便,占用空间少。
网络通信协议
TCP:
- 传输控制协议 (Transmission Control Protocol)。TCP协议是
面向连接
的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。UDP:
- 用户数据报协议(User Datagram Protocol)。UDP协议是一个
面向无连接
的协议。传输数据时,不需要建立连接,不管对方端服务是否启动,直接将数据、数据源和目的地都封装在数据包中,直接发送。每个数据包的大小限制在64k以内。它是不可靠协议,因为无连接,所以传输速度快,但是容易丢失数据。三次握手:
- TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接。
OSI模型:
- 应用层
- 表示层
- 会话层
- 传输层
- 网络层
- 数据链路层
- 物理层
TCP/IP模型:
- 应用层(应用层、表示层、会话层)
- 传输层TCP、UDP
- 网络层IP、ARP、ICMP
- 物理+数据链路层
IP地址-域名-端口号
ip地址:
- 概念:用于唯一标识网络中每台计算机
- 查看IP地址指令:ipconfig
- IP地址表示为十进制(xx.xx.xx.xx),范围0~255
- 组成:网络地址+主机地址
- IP4使用4字节32位,IP6使用16字节128位
- 本机域名:localhost/127.0.0.1
域名:
- 例如:www.baidu.com
- 为了解决记忆IP地址的困难,将IP地址映射为域名,访问时DNS会将域名解析成一个ip地址
端口号:
- 概念:用于标记计算机上某个特定的网络程序
- 表示形式:整数形式,范围0~65525
- 0~1024已被占用,如http-80、ftp-21、ssh-22
- 常见程序默认端口号:tomcat:8080、mysqp:3306、oracle:1521、sqlserver:1433
netstat -an|more
可查看当前主机网络情况,包括端口监听与网络连接netstat -anb
查看网络情况,同时显示使用端口的对应程序
InetAddress类
概述:Java提供了InetAddress类来代表IP地址,InetAddress下还有两个子类:Inet4Address、Inet6Address。
获取实例对象:
public static InetAddress getLocalHost() //返回本地主机的InetAddress对象。 public static InetAddress getByName(String host) //根据提供的主机名和IP地址创建InetAddress对象。 public static InetAddress getByAddress(byte[] addr) //根据提供的原始IP地址创建InetAddress对象。
常用方法:
public String getHostName() //获取此IP地址的主机名。 public String getHostAddress() //返回文本显示中的IP地址字符串。 public byte[] getAddress() //返回此InetAddress对象的原始IP地址。
ServerSocket类
概述:这个类实现了服务器套接字。 服务器套接字等待通过网络进入的请求。ServerSocket对象就代表服务器端程序。
构造方法:
ServerSocket(int port); //创建绑定到指定端口的服务器套接字。 ServerSocket(int port, int backlog) //创建服务器套接字并将其绑定到指定的本地端口号,并指定了连接请求的最大队列长度。
核心方法:
Socket accept() //等待客户端连接并获得与客户端关联的Socket对象。 void close() //关闭此套接字。 InetAddress getInetAddress() //返回此服务器套接字的本地地址。 int getLocalPort() //返回此套接字正在侦听的端口号。
Socket类
概述: Socket开发网络程序被广泛应用,通信两端都要有Socket,相对于是两台机器通信的端点。Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。TCP网络通讯时当客户端连接服务端后,实际上客户端也是通过一个端口和服务端进行通讯的,该端口号是由TCP/IP随机分配的。
构造方法:
public Socket(String host, int port); //根据ip地址字符串和端口号创建客户端Socket对象 public Socket(InetAddress address,int port); //创建流套接字并将其连接到指定IP地址的指定端口号。
核心方法:
OutputStream getOutputStream(); // 获得字节输出流对象 InputStream getInputStream(); // 获得字节输入流对象 InetAddress getInetAddress(); //返回套接字所连接的地址,若未连接返回null InetAddress getLocalAddress(); //获取套接字所绑定的本地地址,若套接字关闭或未绑定,则为通配符地址。 int getPort() //返回此套接字连接到的远程端口号。
TCP通讯案例
//基于TCP通信-服务端
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9888);
System.out.println("服务端服务已开启~~~");
Socket server = serverSocket.accept();
//阻塞等待客户端接入
InputStream IS = server.getInputStream();
BufferedInputStream BIS = new BufferedInputStream(IS);
OutputStream OS = server.getOutputStream();
BufferedOutputStream BOS = new BufferedOutputStream(OS);
byte[] arr = new byte[50];
int location = -1;
StringBuffer clientinformation = new StringBuffer();
while ((location = BIS.read(arr)) != -1) {
clientinformation.append(new String(arr, 0, location));
}//读客户端发送消息,输出控制台
String information = clientinformation.toString();
if ("你好服务端,我来下载文件".equals(information)) {
byte[] fileArr = FileUtils.readFileToByteArray(
new File("Day12\\src\\com\\lxl\\homework\\stu.txt"));
//利用commons-io工具将文件转换字节文件
BOS.write(fileArr);
BOS.flush();
server.shutdownOutput();
} else {
BOS.write("该请求无法理解".getBytes());
BOS.flush();
server.shutdownOutput();
}
System.out.println("服务端响应完毕");
BOS.close();
BIS.close();
server.close();
}
public static void main(String[] args) throws IOException {
Socket client = new Socket("127.0.0.1", 9888);
OutputStream OS = client.getOutputStream();
//获取socket套接字的输出流对象
BufferedOutputStream BOS = new BufferedOutputStream(OS);
//为了提高文件输出效率,使用包装流代理原本的socket的字节流
BOS.write("你好服务端,我来下载文件".getBytes());
BOS.flush();
//确保包装流的缓冲区内容全部写出,否则可能造成传输内容不全面
client.shutdownOutput();
//写出结束标识,底层关闭socket输出流,告诉服务端:客户端写出结束
//因为包装类的缓冲区buf在BOS对象上,而shutdowOutput()关闭OS流
//即绕过了BOS的flushBuffer()没将缓冲区内容写出
//所以务必在shutdown()前调用包装流的flush(),否则可能传输内容丢失!!!
InputStream IS = client.getInputStream();
BufferedInputStream BIS = new BufferedInputStream(IS);
ByteArrayOutputStream BAOS = new ByteArrayOutputStream();
//定义BAOS来存储每次读取文件字节
byte[] fileArr = new byte[1024];
int location = -1;
while ((location = BIS.read(fileArr)) != -1) {
BAOS.write(fileArr, 0, location);
}
FileUtils.writeByteArrayToFile(new File("Server_"
+ new Random().nextInt() + ".txt"), BAOS.toByteArray());
//利用commons-io工具将文件字节数组写出为文件
System.out.println("已接收文件,完成传输~");
BOS.close();
BIS.close();
client.close();
}
UDP网络编程
概述:类
DatagramSocket
和DatagramPacket
实现了基于UDP协议网络程序,UDP数据报通过数据报套接字DatagramSocket发送和接受,系统不保证数据报安全稳定送达,也不确定送达时间。UDP协议中每个数据报都给出了完整地址信息,因此无需建立两端连接DatagramSocket类:
//构造器: publicDatagramSocket() //构造数据报套接字并将其绑定到本地主机上的任何可用端口 DatagramSocket(int port) //构造数据报套接字并将其绑定到本地主机上的指定端口。 DatagramSocket(int port, InetAddress laddr) //创建一个数据报套接字,绑定到指定的本地地址。 //常用方法: void close() //关闭此数据报套接字。 void connect(InetAddress address, int port) //将套接字连接到此套接字的远程地址。 InetAddress getLocalAddress() //获取套接字所绑定的本地地址。 int getLocalPort() //返回此套接字绑定到的本地主机上的端口号。 InetAddress getInetAddress() //返回此套接字连接到的地址。 void receive(DatagramPacket p) //从此套接字接收数据报包。 void send(DatagramPacket p) //从此套接字发送数据报包。 boolean isClosed() //返回套接字是否关闭。 boolean isConnected() //返回套接字的连接状态。
DatagramPacket类:
//构造器: DatagramPacket(byte[] buf, int length, InetAddress address, int port) //构造用于发送/接收length长度的分组数据报包,指定主机上到指定的端口号。 DatagramPacket(byte[] buf, int offset, int length) //构造用于发送/接收偏移offset的length长度的分组数据报包。 DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) //构造用于发送/接收偏移offset的length长度的分组数据报包,指定主机上到指定的端口号。 DatagramPacket(byte[] buf, int length) //构造用于发送/接收length长度的分组数据报包。 //常用方法: byte[] getData() //返回数据缓冲区。 int getLength() //返回要发送的数据的长度或接收到的数据的长度。 int getOffset() //返回要发送的数据的偏移量或接收到的数据的偏移量。 int getPort() //返回发送数据报的远程主机上的端口号,或从中接收数据报的端口号。 void setAddress(InetAddress iaddr) //设置该数据报发送到的机器的IP地址。 void setData(byte[] buf) //设置此数据包的数据缓冲区。 void setLength(int length) //设置此数据包的长度。 void setPort(int iport) //设置发送此数据报的远程主机上的端口号。
UDP通信实例:
/*基本流程: * 1. 建立发送端、接收端(无服务端、客户端概念) * 2. 发送数据前,建立数据报DatagramPacket对象(装包) * 3. 调用DatagramSocket套接字对象的发送send、接收receive方法 * 4. 接收端等待接收数据报,接收完毕后需拆包使用 * 5. 关闭DatagramSocket对象 */ //基于UDP的网络编程-接收端 DatagramSocket socket = new DatagramSocket(9998); //创建在9998端口接受数据的DatagramSocket对象 byte[] arr = new byte[1024*10];//UDP数据报最大64K DatagramPacket packet = new DatagramPacket(arr, arr.length); //创建接受数据报的DatagramPacket对象 socket.receive(packet);//阻塞等待数据报 //接收数据报,并填充如DatagramPacket对象 int length = packet.getLength();//获取数据报数据字节数组长度 byte[] data = packet.getData(); //获取数据字节数组,本质上返回作为缓冲区的arr String message = new String(data, 0, length); System.out.println(message); socket.close(); //基于UDP的网络编程-发送端 DatagramSocket socket = new DatagramSocket(9996); //创建在9996端口接收数据的DatagramSocket对象 byte[] arr = "今晚去嗨呀~".getBytes();//数组字节数组 DatagramPacket packet = new DatagramPacket(arr, arr.length, InetAddress.getByName("127.0.0.1"), 9998 ); //创建发送的数据报,封装数据字节数组,数组长度,目的主机ip对象,端口号 socket.send(packet);//发送数据报 socket.close();
反射机制
Refletion体系
反射获取类成员
//访问方法
//1.根据方法名和参数列表获取Method对象(任意修饰权限)
//getDeclareMethod(方法名,Class...classes)
Method m = catclass.getDeclareMethod("eat",String.class);
//2.创建类的实例对象
Object cat = catclass.newInstance();
//3.爆破方法
m.setAccessible(true);
//4.调用方法
m.invoke(cat,"I am cat");
//调用静态方法,invoke方法的第一个参数可为null
//访问构造器
//1.获取该类的Class对象
Class catclass = Class.forName("com.lxl.Cat");
//2.获取该Class的private修饰有参、无参构造器
Constructor constructor = catclass.getDeclareConstructor(String.class, int.class);
//3.创建实例,并传入参数(爆破)
constructor.setAccessible(true);
//关闭访问安全检查,爆破
Object cat = constructor.newInstancs("LXL", 1);
类加载器读取配置
//通过Classloader类加载器的流读取配置文件
Properties pros = new Properties();
ClassLoader classloader = Test.class.getClassLoader();
//Test为所在类类名
InputStream in = classloader.getResourAsStream("xxx.properties");
pros.load(in);
注解
基本注解
概述:
- 注解是JDK1.5的新特性,又称元数据,用于修饰解释包、类、方法、属性、构造器、局部变量等数据信息
- 不影响代码逻辑,但注解可以被编译运行
- 标记过时功能,忽略警告等,JavaEE中注解可用来配置应用程序的切面,替代旧版中遗留的繁多代码和XML配置
- 注解相当一种标记,是类的组成部分,可以给类携带一些额外的信息。
- 注解是给机器(jvm)看的,编译器或JVM可以根据注解来完成对应的功能;而注释是给人(程序员)看的!
基本注解:
- @Override:限定某个方法是重写父类方法,只可用于方法
- @Deprecated:用于表示某个程序元素已过时
- @SuppressWarnings:抑制编译器警告
- @author:标记作者
- @version:用于标识对象的版本号,适用范围:文件、类、方法。
元注解
@Retention
指定注解作用范围(RetentionPolicy枚举类)
- SOURCE:源码级别保留,编译后即丢弃。
- CLASS:编译级别保留,编译后的class文件中存在,在jvm运行时丢弃,这是默认值。
- RUNTIME:运行级别保留,编译后的class文件中存
@Target
指定注解可以在那些地方使用(ElementType枚举类)
- ANNOTATION_TYPE:作用在注解上,Target修饰的目标注解B,可用来修饰注解C。
- CONSTRUCTOR:作用在构造方法上
- FIELD:作用在变量属性字段上。
- LOCAL_VARIABLE:作用在局部变量声名上。
- METHOD:作用在方法上
- PACKAGE:作用在包名上。
- PARAMETER:作用在参数上
- TYPE:任何类型,即上面的类型都可以修饰
@Documented
指定注解是否会在javadoc体现@Inherited
子类会继承父类注解
自定义注解
注解本质:
//@SuppressWarnings注解的源代码,发现注解其本质就是一个接口! @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { /** 这里有很多的注释 */ String[] value(); // 注解的属性! }
自定义注解格式:
@Target(ElementType.METHOD)//表示可以修饰任何类型 @Retention(RetentionPolicy.RUNTIME)//该注解运行时可见 public @interface 注解名{ // 里面定义属性即可 //格式1:数据类型 属性名() default 默认值; //格式2:数据类型 属性名(); String[] value(); } /* * 属性适用的数据类型 * 八种数据数据类型(int,short,long,double,byte,char,boolean,float) * String,Class,注解类型,枚举类 * 以上类型的一维数组形式 */
自定义注解使用:
public @interface Book { // 为注解定义属性 String value() default "vip"; } @Book("xxx") // 此处可以写成 @Book(value="xxxx"),还可以省略属性名称value不写 public void method(){}
综合案例:
@PeopleInformation(name = "韦小宝", age = 28, isMarry = true, my = @MyTest) public class People { private String name; private Integer age; private boolean isMarray; } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface PeopleInformation { String name() default "无名氏"; int age() default 18; boolean isMarry() default false; MyTest my(); } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyTest { }