模拟停车场停车
停车场有3个车位,有车的不能停,多个用户可以入位,出库
1.利用队列完成
package com.gec.work;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
/*
停车场有3个车位,有车的不能停,多个用户可以入位,出库
*/
public class Work1 {
public static void main(String[] args) {
//队列
BlockingQueue<Boolean> parkings = new ArrayBlockingQueue<>(3);
//停车线程
Thread park = new Thread(new Parking(parkings),"五凌");
Thread park2 = new Thread(new Parking(parkings),"宝骏730");
Thread park3 = new Thread(new Parking(parkings),"ae86");
Thread park4 = new Thread(new Parking(parkings),"奔驰");
//启动停车线程
park.start();
park2.start();
park3.start();
park4.start();
//出停车位
Thread leave = new Thread(new Leave(parkings),"有车");
leave.start();
}
}
class Parking extends Thread{
private BlockingQueue<Boolean> parkings;
public Parking(BlockingQueue<Boolean> parkings) {
this.parkings = parkings;
}
//停车
@Override
public void run() {
try {
//System.out.println("停车场还有空位:" + parkings.remainingCapacity());
//停车
parkings.put(true);
System.out.println(Thread.currentThread().getName() + "停车");
//模拟停车时间
Thread.sleep(new Random().nextInt(2000)+1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Leave extends Thread{
private BlockingQueue<Boolean> parkings;
public Leave(BlockingQueue<Boolean> parkings) {
this.parkings = parkings;
}
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(1500)+1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
//模拟取车
parkings.take();
System.out.println(Thread.currentThread().getName() + "出去");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
注意:这里可以通过remainingCapacity()方法打印出剩余空位的容量,但是不太准备确,有可能是打印或者线程是任意打印出的问题,所以建议不要打印出空位,不太美观。
效果图:
2.用线程池和Semaphore 完成
package com.gec.work;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class Work1 {
public static void main(String[] args) {
//线程池创建
ExecutorService threadPool = Executors.newCachedThreadPool();
//信号量
Semaphore sp = new Semaphore(3);
//循环
for (int i = 1; i < 10; i++) {
//定义编号
final long num = i;
//提交线程任务
threadPool.submit(new Runnable() {
@Override
public void run() {
//获得信号量
try {
sp.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("停车入库:" + num+"号车主");
//停车时间
try {
Thread.sleep(new Random().nextInt(2500)+1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//出车
sp.release();
System.out.println("出车:" + num+"号车主");
}
});
}
//关闭线程池
threadPool.shutdown();
}
}
注意:这里能不加锁尽量不加,加锁容易导致不能同时进入车库和同时出来,只能进一辆出一辆。
效果图:
java网络编程中的基本概念
IP一般都对应一个域名。
服务器是一个开放在网络中的,可以被其他电脑访问的,提供某些数据服务的,配置很高的电脑。
域名
1. 域名:www.baidu.com
2. 域名后缀: .com/.cn/.org/.net/.xyz等等。
3. 每个域名都指向一个IP地址。
IPv4:4个点分十进制,如192.168.10.235,用户在增多,即将耗尽
IPv6:8个点分十六进制,如ACAC:4567:2222:8745:3900:2242:8645:3901
端口:0~65535
1. 可以这样理解:网线中有65535个管道/电脑是个很大的屋子,每个端口都是一个门。
2. 访问指定ip的指定端口,我们的电脑也会使用一个随机未被占用的端口,每个端口同时只能被一个端口使用。
3. 网络模型和网络协议
OSI模型与TCP
网络协议:
有7层OSI网络模型,java编程主要使用TCP/UDP
IP:互联网传输协议
TCP:传输控制协议
TCP/IP:传输控制协议——网络通讯协议
常用命令
查看本机IP地址,在控制台输入:
ipconfig
检查网络是否连通,在控制台输入:
ping 空格 IP地址
ping 104.193.88.123
特殊的IP地址
本机IP地址:127.0.0.1、localhost 。
端口号
网络的通信,本质上是两个进程(应用程序)的通信。每台计算机都有很多的进程,那么在网络通信时,如何区分这些进程呢?
如果说IP地址可以唯一标识网络中的设备,那么端口号就可以唯一标识设备中的进程(应用程序)了。
端口号:用两个字节表示的整数,它的取值范围是065535。其中,01023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
利用协议+IP地址+端口号 三元组合,就可以标识网络中的进程了,那么进程间的通信就可以利用这个标识与其它进程进行交互。
UDP和TCP编程区别
- UDP是面向无连接的,不可靠的传输
- UDP传输的大小在64KB以内,否则会报超出最大限制异常
- UDP传输效率是更高的
- UDP是轻量级协议
- TCP面向连接,是可靠的连接
- 传输效率比UDP要低
- 传输大小没有限制
- TCP协议是重量级协议
两台计算机进行连接,总有一台服务器,一台客户端。服务器和客户端之间的通信通过端口进行。
UDP协议案例:
客户端
package com.gec.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Client {
public static void main(String[] args) throws IOException {
//创建套接字
DatagramSocket ds = new DatagramSocket();
String str = "6666";
byte[] b = str.getBytes();
//ip地址 跟旁边的同学要进行相互的测试 注意:双方的防火墙要关闭
InetAddress ia = InetAddress.getByName("192.168.88.19");
//数据报包
DatagramPacket dp = new DatagramPacket(b, b.length, ia, 5555);//0-65535之间 1024之前已有使用,不建议使用1024
//发送 套接字发送报文到服务器
ds.send(dp);
//关闭
ds.close();
}
}
服务端
package com.gec.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Server {
public static void main(String[] args) throws IOException {
//创建server套接字
DatagramSocket ds = new DatagramSocket(6666);
byte[] b = new byte[1024];
//创建报文对象
DatagramPacket dp = new DatagramPacket(b, b.length);
//调用receive方法
ds.receive(dp);
//转化为字符显示
String str = new String(b,0,dp.getLength());
System.out.println(str);
//关闭 通常是不关闭的
ds.close();
}
}
注意:在此操作前记得两台电脑关闭所有防火墙,客户端要输入正确服务端的ip地址和端口号,要先启动服务端然后开启客户端。
效果图
TCP协议案例
客户端
package com.gec.tcp;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
//1创建客户端套接字
// 127.0.0.1:本地ip 也可以使用localhost
Socket s = new Socket("192.168.88.33", 9999);
//2调用getOutputStream获得输出流对象
OutputStream os = s.getOutputStream();
//3写数据到服务端
// String str = "中国奥运会获得38金牌";
// byte[] b = str.getBytes();
// os.write(b);
InputStream is = new FileInputStream("file.txt");
byte[] b2 = new byte[10240000];
int len = 0;
while((len = is.read(b2))>0) {
os.write(b2, 0, len);
}
//4关闭资源
os.close();
s.close();
}
}
服务端
package com.gec.tcp;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//serverSocket :服务端套接字
ServerSocket ss = new ServerSocket(9999);
//2调用accept 返回客户端套接字
Socket s = ss.accept();
//3获得输入流对象
InputStream is = s.getInputStream();
//4定义一个数组
byte[] b = new byte[10240000];
int len =0;
//5while循环
while((len = is.read(b)) >0) {
//6组成String输出
String str = new String(b,0,len);
System.out.println(str);
}
//7关闭资源
is.close();
s.close();
ss.close();
}
}
效果图
我这里file.txt文件是放在Day0809文件夹里面的如下图
注意:先在自己电脑里面操作服务端和客户端能不能成功,成功再和别人试试看。
个别问题:
注意:如果你发送的是中文的内容,要查看你们电脑的编码是否一致和不同协议之间无法传输数据。
三次握手
TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
- 第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
- 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
- 第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个交互过程如下图所示。
四次挥手
建立连接非常重要,它是数据正确传输的前提;断开连接同样重要,它让计算机释放不再使用的资源。如果连接不能正常断开,不仅会造成数据传输错误,还会导致套接字不能关闭,持续占用资源,如果并发量高,服务器压力堪忧
- 客户端发送关闭连接请求,并停止发送数据,等待服务器确认
- 服务器发送确认信息,通知客户端收到了断开连接请求,并继续发送剩余数据
- 服务器发送完所有数据后,通知客户端所有信息发送完毕,可以断开
- 客户端再次向服务器发送新,确认断开,并断开连接
写一个简单对话功能
客户端
package com.gec.tcp;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
//1创建客户端套接字
// 127.0.0.1:本地ip 也可以使用localhost
Socket s = new Socket("192.168.88.33", 4424);
//2调用getOutputStream获得输出流对象
OutputStream os = s.getOutputStream();
//3写数据到服务端
// String str = "中国奥运会获得38金牌";
// byte[] b = str.getBytes();
// os.write(b);
Scanner sc = new Scanner(System.in);
System.out.println("——————————————————————————————开始聊天界面——————————————————————————————");
while(true) {
//提示打印
System.out.println("请输入你的对话:");
//输出流
OutputStream os1 =s.getOutputStream();
String str = sc.next();
byte[] b = str.getBytes();
//写入
os1.write(b);
// byte [] b2 = new byte[10240000];
// int len = 0;
// while((len = is.read(b2))>0) {
// os.write(b2, 0, len);
// }
System.out.println("发送成功");
//4关闭资源
// os.close();
// s.close();
}
}
}
服务端
package com.gec.tcp;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(4424);
while(true) {
Socket s = ss.accept();
InputStream is = s.getInputStream();
byte[] b = new byte[10240000];
int len =0;
while((len = is.read(b)) >0) {
String str = new String(b,0,len);
System.out.println(str);
}
}
// is.close();
// s.close();
// ss.close();
}
}
效果图
注意:有兴趣的朋友可以尝试一下,我这里的ip地址是192.168.88.33和端口4424可以改成自己的,如果有更好玩方式的可以发给我研究研究。
URL
a、URL 统一资源定位符,表示Internet上某一资源的地址。
b、URL 由两部分组成:协议名称和资源名称,中间用冒号隔开。
c、在java.net包中,提供了URL类来表示URL。
java中URL地址中文乱码问题
public static void main(String[] args) throws IOException {
//模拟浏览器地址栏输入的关键词
String str = "中国";
//编码
String encode = URLEncoder.encode(str, "utf-8");
System.out.println(str + "编码后:" + encode);
//%E4%B8%AD%E5%9B%BD
//%E4%B8%AD%E5%9B%BD
//模拟后台接收到的编码后的字符串
String str2 = "%E4%B8%AD%E5%9B%BD";
//解码
String decode = URLDecoder.decode(str2, "utf-8");
System.out.println(str2+"解码后:" + decode);
//使用场景:在hmtl/jsp又或者其它页面 防止中文乱码,在提交数据之前先进行编码,后台接收到字符串后进行解码
}
谨记编码关键词encode和解码关键词decode
Java使用URLConnection实现网上图片下载到本地
在public static void main(String[] args) throws IOException {
//创建URL对象
// httpClient jsoup
URL url = new URL("http://www.gz.gov.cn/attachment/6/6829/6829316/7388122.pdf");
//获得urlConnection对象
URLConnection conn = url.openConnection();
try(InputStream is = conn.getInputStream();
OutputStream os = new FileOutputStream(new File("c:/a.pdf"))
){
int len = 0;
byte[] b = new byte[1024];
while((len = is.read(b)) >0) {
os.write(b, 0, len);
}
System.out.println("复制Ok....");
} catch (Exception e) {
e.printStackTrace();
}
}
}
喜欢学习java的英语渣渣一枚,和我一样热爱java的朋友可以和我一起研究,又是掉发的一天。
参考
https://blog.csdn.net/weixin_43088443/article/details/112971240
https://blog.csdn.net/bytws/article/details/78086753
下载相关笔记
https://download.csdn.net/download/weixin_45523942/20923137
https://download.csdn.net/download/weixin_45523942/20930271