概述:在网络通信协议下,不同计算机运行的程序,进行数据传输
比如:通信,视频电话,网游,邮件等
只要是计算机之间通过网络进行数据传输,就有网络编程的存在
一、软件结构
1.C/S结构
概述:全称为Client/Server结构。是指客户端和服务器结构,常见程序有QQ、红蜘蛛、飞秋等软件
2.B/S架构
概述:全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有IE、谷歌、火狐等
两种架构各有优势,但是无论那种架构,都离不开网络的支持,网络编程,就是在一定的协议下,实现两台计算机的通信程序
二、服务器概念
概述:安装了服务器软件的计算机
服务器软件:tomcat
网络通信协议:两台计算机在做数据交互时要遵守的规则,协议会对数据的格式,速率等进行规定,只有都遵守了这个协议,才能完成数据交互
两台计算机想要完成数据交互,需要遵守网络通信协议
通信三要素(ip地址、协议、端口号)
1.IP地址
[IP地址]:计算机的唯一标识,用于两台计算机之间的连接
概述:指的是互联网协议地址(Internet Protocol Address),俗称IP,计算机的唯一标识
作用:可用于计算机和计算机之间的连接
IPV4:32位的二进制数,通常被分为4个字节,表示成啊a,b,c,d的形式,例如192.168.65.100.其中a,b,c,d都是0-255之间的十进制数,那么最多可以表示42亿个
IPV6:为了扩大地址空间,拟通过IPV6重新定义地址空间,采用128位地址长度,每16个字节一组,分为8组十六进制数,表示成ABCD:EF01:2345:6789:ABCD:EF01:2345:6789->号称能给地球的每一粒沙子分配一个IP地址
查看ip命令:ipconfig
特殊的网址:代表的是本机地址,到了哪里都不会变,代表自己
Localhost(主机名,写的是服务器ip):端口号/应用名称/资源
2.协议
TCP:面向连接协议
需要先确认连接,才能进行数据交互
三次握手:
- 第一次握手:客户端向服务器端发出连接请求,等待服务器确认
- 第二次握手:服务器端向客户端回送一个响应,通知客户端收到了连接请求
- 第三次握手:客户端再次向服务器端发送确认信息,确认连接
好处:数据安全,能给数据传输提供一个安全的传输环境
坏处:效率低
TCP协议中的四次挥手:
第一次挥手:客户端向服务器端提出结束连接,让服务器做最后的准备工作,此时,客户端处于半关闭状态,即表示不在向服务器发送数据了,但是还可以接收数据
第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端,并告知上层的应用进程不在接收数据
第三次挥手:服务器发完数据后,会给客户端发送一个释放连接的报文,那么客户端接收后就知道可以正式释放连接了
第四次挥手:客户端接收到服务器的最后释放连接报文后,要回复一个彻底断开的报文,这样服务器收到后才会彻底释放连接,这里客户端,发送完最后的报文后,会等待2MSL,因为有可能服务器没有收到最后的报文,那么服务器迟迟没有收到就会再次给客户端发送释放连接的报文,此时客户端在等待时间范围内接收到,会重新发送最后的报文,并重新计时如果等待2MSL后,没有收到,那么彻底断开
UDP:面向无连接协议
好处:效率高
坏处:传输的数据不安全,容易丢失数据包
三、UDP协议编程
DatagramSocket->好比寄快递找的快递公司
DatagramPacket->好比快递公司打包
1.客户端(发送端)
创建DatagramSocket对象(快递公司)
空参:端口号从可用的端口号中随机一个使用
有参:自己指定
创建:DatagramPacket对象,将数据进行打包
要发送的数据->byte[]
指定接收端的IP
指定接收端的端口号
发送数据
释放资源
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Send {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket();
byte[] bytes = "你好呀".getBytes();
InetAddress ip = InetAddress.getByName("192.168.218.1");
int port=6666;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,ip,port);
socket.send(dp);
socket.close();
}
}
2.服务端(接收端)
创建DatagramSocket对象,指定服务端的端口号
接收数据包
解析数据包
释放资源
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Receive {
public static void main(String[] args) throws Exception{
DatagramSocket socket = new DatagramSocket(6666);
byte[] bytes = new byte[1024];//用来保存接收过来的数据
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
socket.receive(dp);
byte[] data = dp.getData();//接收数据
int len = dp.getLength();//从数据包中获取多少数据
InetAddress address = dp.getAddress();//获取发送端的主机
int port = dp.getPort();//发送端的端口号
System.out.println(new String(data,0,len));
System.out.println(address+"..."+port);
socket.close();
}
}
四、TCP协议编程
1.编写客户端
创建Socket对象,指明服务端的ip以及端口号
电泳Socket中的getOutputStream,往服务端发送请求
调用socket中的getInputStream,读取服务端响应回来的数据
关流
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception{
Socket socket = new Socket("192.168.218.1",6666);
OutputStream os = socket.getOutputStream();
os.write("我想看电视".getBytes());
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
is.close();
os.close();
socket.close();
}
}
2.编写服务端
创建ServerSocket对象,设置端口号
调用ServerSocket中的accept方法,等待客户端连接,返回Socket对象
调用socket中的getInputStream,用于读取客户端发送过来的数据
调用socket中的getOutputStream,用于给客户端响应数据
关闭资源
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(6666);
Socket socket = ss.accept();
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
OutputStream os = socket.getOutputStream();
os.write("让你看电视".getBytes());
os.close();
is.close();
socket.close();
ss.close();
}
}
五、文件上传客户端以及服务器实现
public class UUID {
public static void main(String[] args) {
String string = java.util.UUID.randomUUID().toString();
System.out.println("string="+string);
}
}
import com.sun.org.apache.xpath.internal.operations.String;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws Exception{
Socket socket = new Socket("192.168.218.1", 6666);
FileInputStream fis = new FileInputStream("udp\\1.jpg");
OutputStream os = socket.getOutputStream();
byte[] bytes = new byte[1024];
int len;
while ((len=fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//给服务端写一个结束标记
socket.shutdownOutput();
System.out.println("=======以下代码读取响应的结果========");
InputStream is = socket.getInputStream();
byte[] bytes1 = new byte[1024];
int len1 = is.read(bytes1);
System.out.println(new java.lang.String(bytes1,0,len1));
is.close();
os.close();
fis.close();
socket.close();
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class CloseUtils {
private CloseUtils(){
}
public static void closeQ(Socket socket, FileOutputStream fos, InputStream is, OutputStream os){
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
public class SeverThread {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(6666);
while (true){
//调用accept方法等待客户端连接
Socket socket = ss.accept();
new Thread(new Runnable() {
@Override
public void run() {
InputStream is=null;
FileOutputStream fos=null;
OutputStream os=null;
try {
is = socket.getInputStream();
/*
*
*UUID调用randomUUID(),在调用tostring,将其转换成string
* */
String s= UUID.randomUUID().toString();
String name=s+System.currentTimeMillis();
fos = new FileOutputStream("udp\\1.jpg"+name+".jpg");
byte[] bytes = new byte[1024];
int len;
while ((len=is.read(bytes))!=-1){
fos.write(bytes,0,len);
}
System.out.println("=======以下给客户端的响应结果========");
os = socket.getOutputStream();
os.write("上传成功".getBytes());
}catch (Exception e){
e.printStackTrace();
}finally {
CloseUtils.closeQ(socket, fos, is, os);
}
}
}).start();
}
}
}
六、正则表达式
概述:是一个具有特殊规则的字符串
作用:校验
比如:校验手机号,身份证号,密码,用户名,邮箱等(格式,要有大写字母,固定格式)
String中有一个校验正则的方法:
Boolean matches(String regex) 校验字符串是否符合指向的regex的规则
比如:校验QQ号(不能以0开头,必须都是数字,必须是5-15位的)
import java.util.Scanner;
public class Demo01Regex {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String data = scanner.next();
// boolean result01=method01(data);
// System.out.println(result01);
boolean result02=method02(data);
}
private static boolean method02(String data) {
boolean result = data.matches("[1-9][0-9][4,14]");
return result;
}
private static boolean method01(String data) {
if (data.startsWith("0")){
return false;
}
//必须都是数字
char[] chars = data.toCharArray();
for (char aChar : chars) {
if (aChar<'0'||aChar>'9'){
return false;
}
}
//必须是5-15
if (data.length()<5||data.length()>15){
return false;
}
return true;
}
}
1.正则表达式-字符类
java.util.regx.Pattern:正则表达式的编译表示形式
正则表达式-字符类:[]表示一个区间,范围可以自己定义
语法:
[abc]:代表a或者b,或者c字符中的一个
[^abc]:代表除了abc以外的任何字符
[a-z]:代表a-z的所有小写字符中的一个
[A-Z]:代表A-Z的所有大写字符中的一个
[0-9]:代表0-9之间的某一个数学字符
[a-za-Z0-9]:代表a-z或者A-Z或者0-9之间的任意一个字符
[a-dm-p]:a到d或m到p之间的任意一个字符
2.正则表达式-逻辑运算符
正则表达式-逻辑运算符
语法:
&&:并且
|:或者
3.正则表达式-预定义字符
语法:
“.”:匹配任何字符
“\\d”:任何数字[0-9]的简写
“\\D”:任何非数字[^0-9]的简写
“\\s”:空白字符:[\t\n\x08\f\r]的简写
“\\S”:非空白字符:[^\s]的简写
“\\w”:单词字符:[a-zA-Z_0-9]的简写
“\\W”:非单词字符:[^\W]
4.正则表达式-数量词
语法:X代表字符
X?:x出现的数量为0次或1次
X*:x出现的数量为0次到多次 任意次
X+:x出现的数量为1次或者多次 X>=1次
X{n}:x出现的数量为恰好n次X=n
X{n,}:x出现的数量至少为n次 X>=n次
X{n,m}:x出现的数量为n到m次(n和m都是包含的)
5.正则表达式-分组括号()
正则表达式-分组括号() (abc)
6.String类中和正则表达式相关的方法
boolean matches(String regex)判断字符串是否匹配给定的正则表达式
String[] split(String regex)根据给定的正则表达式的匹配拆分此字符串
String replaceAll(String regex,String replacement)把满足正则表达式的字符串,替换为新的字符
7.正则表达式的生成网站
https://www.sojson.com/regex/generate
import java.util.Arrays;
public class Demo02Regex {
public static void main(String[] args) {
// method01();
// method02();
// method03();
//method04();
// method05();
method06();
}
private static void method06() {
String s1="abc hahah hehe hdhshsh";
String[] arr1 = s1.split(" +");
System.out.println(Arrays.toString(arr1));
String s2=s1.replaceAll(" +","z");
System.out.println(s2);
}
//分组括号
private static void method05() {
//校验abc可以出现任意次
boolean matches = "abcabc".matches("(abc)*");
System.out.println(matches);
}
//数量词
private static void method04() {
//验证字符串是否是三位数字
boolean result01="111".matches("\\d{3}");
System.out.println(result01);
//验证手机号 1开头第二位3 5 8 剩下的都是0-9
boolean matches = "13838381438".matches("[1][358]\\d{9}");
System.out.println(matches);
}
//预定义字符
private static void method03() {
//验证字符串是否是三位数字
// boolean result01="111".matches("[0-9][0-9][0-9]");
boolean result01="111".matches("\\d\\d\\d");
System.out.println(result01);
//验证手机号 1开头第二位3 5 8 剩下的都是0-9
boolean matches = "13838381438".matches("[1][358]\\d\\d\\d\\d\\d\\d\\d\\d\\d");
System.out.println(matches);
}
//逻辑运算符
private static void method02() {
//要求字符串是小写字母并且字符不能以[aeiou]开头,后面跟ad
boolean result01 = "add".matches("[[a-z]&&[^aeiou]][a][d]");
System.out.println(result01);
}
//字符类
private static void method01() {
//验证字符串是否以h开头,d结尾,中间是aeiou的某一个字符
boolean result01="hyd".matches("[h][aeiou][d]");
System.out.println(result01);
}
}
七、Lombok
Lombok
作用:简化javabean开发的
使用:
下插件->如果是idea2022以后不需要下载,自带
导lombok的jar包
修改设置
1.Lombok常用的注解
@Getter和Setter
作用:生成成员变量的get和set方法
写在成员变量上,只对当前成员变量有效
写在类上,对所有成员变量有效
注意:静态成员变量无效
@ToString
作用:生成tostring()方法
注解只能写在类上
@NoArgsContructor和@AlllArgsContstructor
@NoArgsContructor:无参构造
@AlllArgsContstructor:有参构造
@EqualsAndHashCode
作用:生成hashCode()和equals()方法
注解只能写在类上
@Data
作用:生成get/set,tostring,hashCode,equals,无参构造方法
注解只能写在类上