线程通信
多线程之间打成通信沟通的效果,协作完成业务需求

Object:
wait() 线程等待 当调用某一个对象 的wait方法,当前线程就会进入到与这个对象相关的等待池中进行等待—>等待阻塞,等待被唤醒
会让出cpu的资源,并且会释放对象的锁
notify() 唤醒线程 当调用一个对象的notify方法,会唤醒当前对象等待池中正在等待的线程,唤醒某一个
这个线程会进入到就绪状态,要想要运行: 1)cpu的调度 2)获取对象锁

wait(ms) 阻塞等待指定时间
notifyAll() 唤醒全部

wait与notify必须使用在一个同步环境下,用于控制多线程之间协调工作问题,保证数据安全

sleep与wait之间区别
sleep : 线程休眠 抱着资源睡觉: 让出cpu资源,抱着对象的锁

人车共用街道:
街道 : 红绿灯 boolean flag 绿灯–>人走 true 红灯–>车走 false ns南北走向 we东西走向
人 : ns南北
车 : we东西

生产者消费者模式:
通过信号灯法
*/
public class Class001_Wait {
public static void main(String[] args) {
Street street = new Street(); //共享街道
new Thread(new Person(street)).start();
new Thread(new Car(street)).start();
}
}

//街道
class Street{
//红绿灯
private boolean flag = false;

//ns
public synchronized void ns(){
//判断是否为绿灯
if(flag){
/* try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println(“人走……”);
//红绿灯变为红灯
flag=false;
//唤醒对方线程
this.notify();
//自己等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}

}
}

//we
public synchronized void we(){
if(!flag){
/*try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println(“车走……”);
//红绿灯变为红灯
flag=true;
//唤醒对方线程
this.notify();
//自己等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//人
class Person implements Runnable{
//街道
private Street street = null;

public Person(Street street) {
this.street = street;
}

@Override
public void run() {
while(true){
street.ns();
}
}
}

//车
class Car implements Runnable{
//街道
private Street street = null;

public Car(Street street) {
this.street = street;
}

@Override
public void run() {
while(true){
street.we();
}
}
}

网页编程 : 上层的应用
网络编程 : 底层,关注数据如何传输,如何存储
节点 : 网络电子设备
节点与节点之间组成网络
IP : 表示节点
端口 : 区分不同的软件
URL : 互联网中资源的指针,统一资源定位符
协议 : 合同,标准,规范
传输层协议 :
UDP : 相当于写信 只管写只管发 效率高 不安全 大小存在限制
TCP : 相当于打电话 面向连接 安全性高 效率低 大小没有限制 ****

IP :
定义网络中的节点 (网络电子设备,手机,电脑,路由器…)
分为 : IPV4(4个字节,32位) IPV6 (128位)
特殊IP:
192.168.0.0~192.168.255.255 非注册IP,供组织内部使用
127.0.0.1 本地IP
localhost : 本地域名
域名与IP之间的关系: DNS解析器

java.net包
InetAddress 类表示Internet协议(IP)地址

*/
public class Class001_IP {
public static void main(String[] args) throws UnknownHostException {
//static InetAddress getByName(String host) 根据主机名称确定主机的IP地址。
//static InetAddress getLocalHost() 返回本地主机的地址。
InetAddress address1 = InetAddress.getLocalHost();
System.out.println(address1); //DESKTOP-KHNV6UD/192.168.16.236
System.out.println(address1.getHostName());
System.out.println(address1.getHostAddress());

InetAddress address2 = InetAddress.getByName(“www.baidu.com”);
System.out.println(address2);
System.out.println(address2.getHostName());
System.out.println(address2.getHostAddress());
}
}

IP : 定位节点
端口 : 区分软件
端口号 2个字节 0~65535
同一协议下端口号不能冲突
建议使用8000以上的,8000以下称为预留端口

常见的端口:
80 : http
8080 : tomcat
1521 : Oracle
3306 : Mysql

InetSocketAddress 此类实现IP套接字地址(IP地址+端口号)它也可以是一对(主机名+端口

public class Class002_Port {
public static void main(String[] args) {
//InetSocketAddress(String hostname, int port) 根据主机名和端口号创建套接字地址。
//InetSocketAddress(InetAddress addr, int port) 根据IP地址和端口号创建套接字地址。
InetSocketAddress in = new InetSocketAddress(“localhost”,8989);
System.out.println(in);
System.out.println(in.getHostName());
System.out.println(in.getPort());
}
}

URL
同一资源定位符,指向万维网上的“资源”的指针。

组成:
协议: http
域名: www.baidu.com
端口号: 80
资源: index.html
提交数据: name=zhangsan&pwd=123
锚点: #a

互联网 的三大基石:
html
http
url

URL 类

public class Class003_URL {
public static void main(String[] args) throws MalformedURLException {
//URL(String spec) 从 String表示创建 URL对象。
//URL(String protocol, String host, int port, String file)
URL url = new URL(“https://www.baidu.com:80/index.html?name=zhangsan&pwd=123#a”);

System.out.println(url);
System.out.println(“协议:”+url.getProtocol());
System.out.println(“域名:”+url.getHost());
System.out.println(“端口:”+url.getPort());
System.out.println(“资源:”+url.getFile());
System.out.println(“资源:”+url.getPath());
System.out.println(“资源:”+url.getQuery());
System.out.println(“资源:”+url.getRef());
}
}

网络爬虫

public class Class004_Spider {
public static void main(String[] args) throws IOException {
//1.定义URL
URL url = new URL(“https://www.baidu.com/index.html”);
//2.获取流 : InputStream openStream() 打开与此 URL的连接并返回 InputStream以从该连接读取。
InputStream is = url.openStream();
//InputStreamReader 字节输入流转位字符输入流的节点流–>功能流
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String msg = null;
//3.读入操作
while((msg = rd.readLine())!=null){
System.out.println(msg);
}
//4.关闭
rd.close();
is.close();
}
}

套接字:
传输层为应用层开辟的小口子
不同协议下Socket实现不同
UDP与TCP协议对Socket实现

UDP : 相当于写信|有包裹|发短信 非面向连接 协议简单,开销小,效率高 不安全 大小由限制(一般不超过60k)
TCP : 相当于打电话 面向连接 效率低 安全 大小没有限制
基于三次握手

UDP协议下发送端与接收端两端平等
DatagramSocket 此类表示用于发送和接收数据报包的套接字。
DatagramSocket(int port) 构造一个数据报套接字并将其绑定到本地主机上的指定端口。
void receive(DatagramPacket p) 从此套接字接收数据报包。
void send(DatagramPacket p) 从此套接字发送数据报包。

DatagramPacket 该类表示数据报包。
byte[] getData() 返回数据缓冲区。
int getLength() 返回要发送的数据的长度或接收的数据的长度。

数据的传输基于字节数组

UDP实现发送端: 基本流程
1.定义我是发送端
2.准备数据
3.打包
4.发送
5.关闭

*/
public class Class001_Send {
public static void main(String[] args) throws IOException {
// 1.定义我是发送端
DatagramSocket s = new DatagramSocket(9090);

System.out.println(“————-我是发送端————-“);

// 2.准备数据
byte[] arr = “你好”.getBytes();
// 3.打包
DatagramPacket packet = new DatagramPacket(arr,0,arr.length,new InetSocketAddress(“127.0.0.1”,8989));
// 4.发送
s.send(packet);
// 5.关闭
s.close();
}
}

public class Class002_Receive {
public static void main(String[] args) throws IOException {
//1.定义我是接收端
DatagramSocket r = new DatagramSocket(8989);

System.out.println(“———–我是接收端————“);

//2.准备字节数组,打包
byte[] arr = new byte[1024];
DatagramPacket packet = new DatagramPacket(arr,arr.length);
//3.接收数据
r.receive(packet);
//4.处理数据
//byte[] getData() 返回数据缓冲区。
//int getLength() 返回要发送的数据的长度或接收的数据的长度。
byte[] newArr = packet.getData();
int len = packet.getLength();

System.out.println(new String(newArr,0,len));

//5.关闭
r.close();
}
}

客户端 Socket
Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号。
InputStream getInputStream()
OutputStream getOutputStream()
服务器 ServerSocket 该类实现服务器套接字。
ServerSocket(int port) 创建绑定到指定端口的服务器套接字。
Socket accept() 侦听对此套接字的连接并接受它。

tcp协议下传输数据基于IO流

tcp协议实现基本流程 : 客户端
1.定义我是客户端–>指定要请求的服务器的IP+端口
2.准备数据
3.获取输出流
4.输出–>IO操作
5.刷出
6.关闭
*/
public class Class001_Client {
public static void main(String[] args) throws IOException {
System.out.println(“———–我是客户端————–“);
// 1.定义我是客户端–>指定要请求的服务器的IP+端口
Socket client = new Socket(“localhost”,9999);
System.out.println(“———–与服务器端建立连接————–“);
// 2.准备数据
String str = “你好”;
// 3.获取输出流
DataOutputStream os = new DataOutputStream(new BufferedOutputStream(client.getOutputStream()));
// 4.输出–>IO操作
os.writeUTF(str);
// 5.刷出
os.flush();
// 6.关闭
os.close();
client.close();
}
}

tcp协议实现基本流程 : 服务端
1.定义我是服务端
2.阻塞式监听
3.获取输入流–>接收客户端的请求数据
4.处理数据
5.关闭
*/
public class Class002_Server {
public static void main(String[] args) throws IOException {
System.out.println(“———–我是服务器端———–“);
// 1.定义我是服务端
ServerSocket server = new ServerSocket(9999);
// 2.阻塞式监听
Socket client = server.accept();

System.out.println(“———–一个客户端连接成功———-“);

// 3.获取输入流–>接收客户端的请求数据
DataInputStream is = new DataInputStream(new BufferedInputStream(client.getInputStream()));
String msg = is.readUTF();
// 4.处理数据
System.out.println(msg);
// 5.关闭
is.close();
client.close();
server.close();
}
}

 tcp 单向登录: 客户端1.定义客户端2.准备数据(用户输入)1)输入流2)用户名与密码3.获取输出流向服务器端发送数据(用户名与密码)4.刷出5.关闭 */public class Class003_LoginClient {public static void main(String[] args) throws IOException {System.out.println("-------我是客户端---------");//1.定义客户端Socket client = new Socket("localhost",9898);//2.准备数据(用户输入)//1)输入流BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));//2)用户名与密码System.out.println("请输入用户名");String username = rd.readLine();System.out.println("请输入密码");String password = rd.readLine();System.out.println(username+"-->"+password);//3.获取输出流向服务器端发送数据(用户名与密码)DataOutputStream os = new DataOutputStream(client.getOutputStream());//username=laopei&password=1234os.writeUTF("username="+username+"&password="+password);//4.刷出os.flush();//5.关闭os.close();rd.close();client.close();}}

 tcp 单向登录: 服务端1.定义我是服务器2.阻塞式监听3.获取输入流接收客户端发动的数据4.处理数据5.关闭 要求: 服务器端接收到用户输入的用户名与密码,与指定的laopei,1234比较是否相等,相等本地输出登录成功,不相等输出用户名或密码错误!!! */public class Class003_LoginServer {public static void main(String[] args) throws IOException {System.out.println("--------我是服务器-------");//1.定义我是服务器ServerSocket server = new ServerSocket(9898);//2.阻塞式监听Socket client = server.accept();System.out.println("一个客户端连接成功........");//3.获取输入流接收客户端发动的数据DataInputStream is = new DataInputStream(client.getInputStream());String msg = is.readUTF();//username=laopei&password=1234//4.处理数据System.out.println(msg);//5.关闭is.close();client.close();server.close();}}

 tcp 双向登录: 客户端1.定义客户端2.准备数据(用户输入)1)输入流2)用户名与密码3.获取输出流向服务器端发送数据(用户名与密码)4.刷出5.获取输入流 从服务器端读取响应6.关闭 */public class Class005_LoginTwoWayClient {public static void main(String[] args) throws IOException {System.out.println("-------我是客户端---------");//1.定义客户端Socket client = new Socket("localhost",9898);//2.准备数据(用户输入)//1)输入流BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));//2)用户名与密码System.out.println("请输入用户名");String username = rd.readLine();System.out.println("请输入密码");String password = rd.readLine();System.out.println(username+"-->"+password);//3.获取输出流向服务器端发送数据(用户名与密码)DataOutputStream os = new DataOutputStream(client.getOutputStream());//username=laopei&password=1234os.writeUTF("username="+username+"&password="+password);//4.刷出os.flush();//5.获取输入流 从服务器端读取响应DataInputStream is = new DataInputStream(client.getInputStream());System.out.println(is.readUTF());//6.关闭is.close();os.close();rd.close();client.close();}}

tcp 双向登录: 服务端1.定义我是服务器2.阻塞式监听3.获取输入流接收客户端发动的数据4.处理数据5.获取输出流 把结果响应 给客户端6.刷出7.关闭 要求: 服务器端接收到用户输入的用户名与密码,与指定的laopei,1234比较是否相等,相等本地输出登录成功,不相等输出用户名或密码错误!!! */public class Class006_LoginTwoWayServer {public static void main(String[] args) throws IOException {System.out.println("--------我是服务器-------");//1.定义我是服务器ServerSocket server = new ServerSocket(9898);//2.阻塞式监听Socket client = server.accept();System.out.println("一个客户端连接成功........");//3.获取输入流接收客户端发动的数据DataInputStream is = new DataInputStream(client.getInputStream());String msg = is.readUTF();//username=laopei&password=1234//4.处理数据System.out.println(msg);//处理1)/*String str = "username=laopei&password=1234";if(str.equals(msg)){System.out.println("登录成功");}else{System.out.println("登录失败");}*///2)String username = null;String password = null;String[] strs = msg.split("&");for(String s:strs){String[] arr = s.split("=");if("username".equals(arr[0])){username = arr[1];}else if("password".equals(arr[0])){password = arr[1];}}//5.获取输出流 把结果响应 给客户端DataOutputStream os = new DataOutputStream(client.getOutputStream());if("laopei".equals(username) && "1234".equals(password)){os.writeUTF("登录成功");}else{os.writeUTF("登录失败");}//6.刷出os.flush();//7.关闭os.close();is.close();client.close();server.close();}}
多用户登录服务器端通过循环可以实现多用户登录但是服务器只能排队对不同的客户端做响应 */public class Class007_MulLoginTwoWayServer {public static void main(String[] args) throws IOException {System.out.println("--------我是服务器-------");//1.定义我是服务器ServerSocket server = new ServerSocket(9898);//2.阻塞式监听boolean flag = true;while(flag){ Socket client = server.accept(); System.out.println("一个客户端连接成功........"); //3.获取输入流接收客户端发动的数据 DataInputStream is = new DataInputStream(client.getInputStream()); String msg = is.readUTF(); //4.处理数据 String username = null; String password = null; String[] strs = msg.split("&"); for(String s:strs){ String[] arr = s.split("="); if("username".equals(arr[0])){ username = arr[1]; }else if("password".equals(arr[0])){ password = arr[1]; } } //5.获取输出流 把结果响应 给客户端 DataOutputStream os = new DataOutputStream(client.getOutputStream()); if("laopei".equals(username) && "1234".equals(password)){ os.writeUTF("登录成功"); }else{ os.writeUTF("登录失败"); } //6.刷出 os.flush(); //7.关闭 os.close(); is.close(); client.close(); }server.close();}}

多用户登录服务器端  通过多线程实现 */public class Class008_MulLoginTwoWayServer {public static void main(String[] args) throws IOException {System.out.println("--------我是服务器-------");//1.定义我是服务器ServerSocket server = new ServerSocket(9898);//2.阻塞式监听boolean flag = true;while(flag){ Socket client = server.accept(); System.out.println("一个客户端连接成功........"); //开启线程为上面监听到客户端响应new Thread(new Channel(client)).start(); }server.close();}static class Channel implements Runnable{private Socket client = null;private DataInputStream is = null;privateDataOutputStream os = null;public Channel(Socket client) {this.client = client;try {is = new DataInputStream(client.getInputStream());os = new DataOutputStream(client.getOutputStream());} catch (IOException e) {e.printStackTrace();}}//读入数据public String read(){String msg = null;try {msg = is.readUTF();} catch (IOException e) {e.printStackTrace();}return msg;}//写出public void write(String msg){try {os.writeUTF(msg);os.flush();} catch (IOException e) {e.printStackTrace();}}//关闭资源public void close(){if(os!=null){try {os.close();} catch (IOException e) {e.printStackTrace();}}if(is!=null){try {is.close();} catch (IOException e) {e.printStackTrace();}}if(client!=null){try {client.close();} catch (IOException e) {e.printStackTrace();}}}@Overridepublic void run() {//获取输入流接收客户端发动的数据String msg = read();//处理数据String username = null;String password = null;String[] strs = msg.split("&");for(String s:strs){String[] arr = s.split("=");if("username".equals(arr[0])){username = arr[1];}else if("password".equals(arr[0])){password = arr[1];}}//获取输出流 把结果响应 给客户端if("laopei".equals(username) && "1234".equals(password)){write("登录成功");}else{write("登录失败");}//关闭close();}}}