day12【JUnit单元测试、网络编程】
今日目标:
a.Junit单元测试[重点]
b.UDP
c.TCP
d.http[重点,在服务器阶段学习]
第一章.Junit单元测试
1.什么是单元测试
简单的理解: 单元测试就是可以取代main方法进行测试的技术
2.Junit的使用步骤
-
下载
http://www.junit.org 大部分的开发工具(IDEA,Eclipse,MyEclipse)都会集成junit的jar包
-
具体使用步骤
a.编写被测试类(业务类) b.编写测试类 c.在测试类编写测试方法(不需要main方法!!!) d.给测试方法加上junit提供的注解@Test
-
运行测试
在Junit的测试方法上右键运行该方法 在Junit的测试类上右键运行该类中所有的测试方法
3.单元测试中其他四个注解
-
Junit4.x
@Before 表示该方法会在每个测试方法执行之前执行 @After 表示该方法会在每个测试方法执行之后执行 @BeforeClass 表示该方法会在所有测试方法执行之前执行 @AfterClass 表示该方法会在所有测试方法执行之后执行 注意:@BeforeClass和@AfterClass必须修饰静态方法
-
Junit5.x
@BeforeEach 表示该方法会在每个测试方法执行之前执行 @AfterEach 表示该方法会在每个测试方法执行之后执行 @BeforeAll 表示该方法会在所有测试方法执行之前执行 @AfterAll 表示该方法会在所有测试方法执行之后执行 注意:@BeforeAll和@AfterAll必须修饰静态方法
第二章 网络编程入门
1.软件架构介绍
BS架构: Browser(浏览器)/Server(服务器)
比如: QQ,淘宝,京东
CS架构: Client(客户端)/Server(服务器)
比如: QQ(微信),百度云,迅雷,淘宝,京东
我们JavaEE主要学:服务器,但是也会学7天左右浏览器相关的语言
2.网络通信协议介绍
网络通信协议:互联网上计算机之间数据交换需要遵循的规则
3.常用的通信协议
IP协议: 规定每台连接到网络的计算机的唯一标识(IP地址)
UDP协议: 用户数据报协议
特点: 面向无连接
优点: 性能较高
缺点: 数据不能保证安全性和完整性
比如: 直播,QQ视频,供屏软件
TCP协议: 传输控制协议
特点: 面向有链接(建立连接的过程,称为"三次握手")
优点: 保证数据是安全的和完整的
缺点: 性能较低
比如: 下载游戏
4.网络编程的三要素
网络协议(UDP和TCP):必须遵循的规则
IP地址: 计算机的唯一标识
端口号: 计算机中软件的标识
端口号有0-65535,我们开发时建议使用1024以上端口,因为1024以下端口被知名软件服务占用了
扩展:
-
IP地址的未来
IPv4: 由32位二进制组成(4个字节),比如(192.168.109.23),一共有多个IP? 42亿种IP IPv6: 由128位二进制组成(16个字节),一共有多少个IP??号称可以给全球每一粒沙子搞一个IP,且不重复
-
IP地址的获取和测试(Dos命令)
ipconfig: 查看本机IP ping 其他人IP: 测试网络是否畅通
-
特殊的IP地址
127.0.0.1(localhost) 本机IP(相当于Java中this)
第三章 UDP通信
1.UDP协议概述
UDP特点: 面向无连接
* 面向无连接的协议
* 发送端只管发送,不确认对方是否能收到。
* 基于数据包进行数据传输。
* 发送数据的大小限制64K以内
* 因为面向无连接,速度快,但是不可靠。
UDP协议的使用场景
* 即时通讯
* 在线视频
* 网络语音电话
2.UDP的发送端类和数据包类
a.数据发送/接收器: DatagramSocket
DatagramSocket
构造方法:
public DatagramSocket(); -- 一般用于发送端
public DatagramSocket(int port); -- 一般用于接收端
成员方法:
public void send(DatagramPacket dp); -- 发送数据包
public void receive(DatagramPacket dp); -- 接收数据包
b.数据包类 : DatagramPacket
DatagramPacket
构造方法:
public DatagramPacket(byte[] buf, int length, InetAddress address, int port);
要发送的字节数组,要发送的字节数组长度,接收人的IP地址,接收人的端口号
public DatagramPacket(byte[] buf, int length);
接收数据的字节数组,数组中用于接收数据的长度
3.UDP通信案例
/**
* UDP发送端
*/
public class UDPSender {
public static void main(String[] args) throws IOException {
//1.创建一个发送器对象
DatagramSocket ds = new DatagramSocket();
//2.创建一个数据报对象
byte[] bs = "Hello,我是发送端".getBytes();
DatagramPacket dp = new DatagramPacket(bs,bs.length, InetAddress.getByName("127.0.0.1"),12345);
//3.发送数据
ds.send(dp);
System.out.println("发送成功...");
//4.释放资源
ds.close();
}
}
/**
* UDP接收端
*/
public class UDPReceiver {
public static void main(String[] args) throws IOException {
//1.创建一个接收器对象
DatagramSocket ds = new DatagramSocket(12345);
//2.创建一个数据报对象
byte[] bs = new byte[1024];
DatagramPacket dp = new DatagramPacket(bs, bs.length);
//3.接收数据包
System.out.println("等待发送端的信息...");
ds.receive(dp); // 该方法具有阻塞功能,直到有发送端发送信息
System.out.println("发送端发来信息...");
//输出一下
int len = dp.getLength();
byte[] data = dp.getData();
System.out.println("发送端发来贺电:" + new String(data, 0, len));
//4.释放
ds.close();
}
}
第四章 TCP通信
1.TCP通信分为客户端和服务器
客户端: 一般是指个人电脑(配置较低)
服务器端: 一般是指企业电脑(配置较高)
2.TCP中的两个重要的类
Socket(套接字)类,代表客户端的类
ServerSocket(服务器套接字)类,代表服务器的类
3.Socket类的介绍和使用
-
构造方法
public Socket(String host, int port); 创建客户端时,要指定服务器的IP和端口号 该构造非常牛逼, 如果指定的服务器存在,那么构造方法自动和服务器通过TCP建立连接,对象成功创建 如果指定的服务器不存在,那么该构造方法直接抛出异常
-
常用方法
public OutputStream getOutputStream(); 获取连接通道中的输出流 public InputStream getInputStream(); 获取连接通道中的输入流 public void shutDownOutput(); 关闭连接通道中的输出流 public void shutDownInput(); 关闭连接通道中的输入流 public void close(); 关闭客户端,与服务器断开连接(连接通道中的流也会自动关闭)
4.ServerSocket类的介绍和使用
-
构造方法
public ServerSocket(int port); 创建服务器,指定服务器所在的端口号
-
常用的成员方法
public void close(); 关闭服务器(断开所有客户端连接) public Socket accept(); 接收客户端连接,返回连接到的客户端对象
5.简单的TCP通信实现(单向通信)
/**
* TCP的客户端
*/
public class TCPClient {
public static void main(String[] args) throws IOException, InterruptedException {
//1.创建客户端,同时连接服务器
Socket s = new Socket("127.0.0.1",54321);
System.out.println("服务器连接成功...");
//2.获取通道中的输出流
OutputStream out = s.getOutputStream();
//3.调用out的write方法
Thread.sleep(5000);
out.write("你好,服务器,我是客户端,你大爷我来了...".getBytes());
System.out.println("数据发送成功...");
//4.释放资源
out.close();
s.close();
System.out.println("客户端关闭成功...");
}
}
/**
* TCP服务器端
*/
public class TCPServer {
public static void main(String[] args) throws IOException {
//1.创建一个服务器
ServerSocket server = new ServerSocket(54321);
System.out.println("服务器启动..");
//2.等待接收客户端
System.out.println("等待客户端...");
Socket s = server.accept(); // 此方法具有阻塞功能
System.out.println("客户端来了...");
//3.获取通道中的输入流
InputStream in = s.getInputStream();
//4.调用in的read方法
byte[] bs = new byte[1024];
System.out.println("正在接收客户端数据...");
int len = in.read(bs); // 此方法具有阻塞功能
System.out.println("客户端说:" + new String(bs, 0, len));
//5.释放资源
in.close();
s.close();
server.close();
System.out.println("服务器关闭成功...");
}
}
注意: 在服务器端有两个方法具有阻塞功能
a.server.accept() 等待客户端连接方法
b.in.read(bs) 等待客户端发送数据
6.简单的TCP通信实现(双向通信)
/**
* TCP的客户端
*/
public class TCPClient {
public static void main(String[] args) throws IOException, InterruptedException {
//1.创建客户端,同时连接服务器
Socket s = new Socket("127.0.0.1",54321);
System.out.println("服务器连接成功...");
//2.获取通道中的输出流
OutputStream out = s.getOutputStream();
//3.调用out的write方法
Thread.sleep(5000);
out.write("你好,服务器,我是客户端,你大爷我来了...".getBytes());
System.out.println("数据发送成功...");
//===========双向===========
//4.获取通道中的输入流
InputStream in = s.getInputStream();
//5.调用in的read方法
System.out.println("等待服务器回信..");
byte[] bs = new byte[1024];
int len = in.read(bs); // 此方法也具有阻塞功能
System.out.println("服务器说:" + new String(bs, 0, len));
//===========双向===========
//6.释放资源
in.close();
out.close();
s.close();
System.out.println("客户端关闭成功...");
}
}
注意:客户端中有一个方法具有阻塞功能
a.in.read(bs) 读取服务器回复的信息
/**
* TCP服务器端
*/
public class TCPServer {
public static void main(String[] args) throws IOException, InterruptedException {
//1.创建一个服务器
ServerSocket server = new ServerSocket(54321);
System.out.println("服务器启动..");
//2.等待接收客户端
System.out.println("等待客户端...");
Socket s = server.accept(); // 此方法具有阻塞功能
System.out.println("客户端来了...");
//3.获取通道中的输入流
InputStream in = s.getInputStream();
//4.调用in的read方法
byte[] bs = new byte[1024];
System.out.println("正在接收客户端数据...");
int len = in.read(bs); // 此方法具有阻塞功能
System.out.println("客户端说:" + new String(bs, 0, len));
//===========双向===========
//5.获取通道中的输出流
OutputStream out = s.getOutputStream();
//6.调用输出流的write方法
Thread.sleep(5000);
out.write("您的消息收到了,您可以安息了...".getBytes());
System.out.println("数据回复成功...");
//===========双向===========
//7.释放资源
out.close();
in.close();
s.close();
server.close();
System.out.println("服务器关闭成功...");
}
}
注意: 在服务器端有两个方法具有阻塞功能
a.server.accept() 等待客户端连接方法
b.in.read(bs) 等待客户端发送数据
第五章 综合案例:文件上传
1.文件上传案例分析(画图演示)

2.文件上传案例实现(代码演示)
/**
* 文件上传的客户端
*/
public class FileUploadClient {
public static void main(String[] args) throws IOException {
// 1.创建客户端连接服务器
Socket client = new Socket("127.0.0.1",6666);
System.out.println("服务器连接成功...");
// 2.获取输出流
OutputStream out = client.getOutputStream();
// 3.创建文件的输入流
FileInputStream fis = new FileInputStream("222.png");
// 循环:一边读文件
// 一边发数据
byte[] bs = new byte[1024];
int len = 0;
System.out.println("正在给服务器发送文件...");
while ((len = fis.read(bs)) != -1) {
out.write(bs, 0, len);
}
client.shutdownOutput();
System.out.println("文件发送完毕...");
// 4.获取输入流
InputStream in = client.getInputStream();
// 5.调用输入流的read方法
byte[] bs1 = new byte[1024];
System.out.println("正在接收服务器的回复...");
int len1 = in.read(bs1);
System.out.println("服务器回复:" + new String(bs1, 0, len1));
// 6.释放资源
in.close();
fis.close();
out.close();
client.close();
System.out.println("客户端关闭...");
}
}
/**
* 文件上传服务器端
*/
public class FileUploadServer {
public static void main(String[] args) throws IOException {
// 1.创建服务器对象
ServerSocket server = new ServerSocket(6666);
System.out.println("服务器启动成功...");
// 2.接收客户端对象
System.out.println("等待客户端...");
Socket client = server.accept();
System.out.println("客户端来了..."+client.getInetAddress().getHostAddress());
// 3.获取输入流
InputStream in = client.getInputStream();
// 4.创建文件的输出流
FileOutputStream fos = new FileOutputStream("G:\\uploads\\copy.png");
// 循环: 一边读数据
// 一边写文件
byte[] bs = new byte[1024];
int len = 0;
System.out.println("正在接收文件....");
while ((len = in.read(bs)) != -1) {
fos.write(bs, 0, len);
}
System.out.println("文件接收完毕...");
// 5.获取输出流
OutputStream out = client.getOutputStream();
// 6.调用输出流的write方法
out.write("您的文件收到了".getBytes());
System.out.println("给客户端回复信息完毕..");
// 7.释放资源
out.close();
fos.close();
in.close();
client.close();
server.close();
System.out.println("服务器关闭!!");
}
}
3.文件上传案例实现的不足之处
a.文件名固定,导致无论上传多少张图片,只剩最后一张
b.服务器每次启动只能服务一个客户端
c.客户端文件很大,服务器无法接收下一个客户端
4.文件上传案例的优化实现(代码演示)
a.文件名固定,导致无论上传多少张图片,只剩最后一张
优化:将图片的名字改为当前的毫秒值
b.服务器每次启动只能服务一个客户端
给服务器添加死循环,永不停止的接收下一个客户端
c.客户端文件很大,服务器无法接收下一个客户端
接收到客户端之后,创建一个线程,与该客户端进行交互,主线立即等待下一个客户端
/**
* 文件上传服务器端
*/
public class FileUploadServer {
public static void main(String[] args) throws IOException {
// 1.创建服务器对象
ServerSocket server = new ServerSocket(6666);
System.out.println("服务器启动成功...");
// 2.接收客户端对象
while (true) {
System.out.println("等待客户端...");
Socket client = server.accept();
System.out.println("客户端来了..." + client.getInetAddress().getHostAddress());
//创建线程
new Thread(new Runnable() {
@Override
public void run() {
try {
// 3.获取输入流
InputStream in = client.getInputStream();
// 4.创建文件的输出流
FileOutputStream fos = new FileOutputStream("G:\\uploads\\" + System.currentTimeMillis() + ".png");
// 循环: 一边读数据
// 一边写文件
byte[] bs = new byte[1024];
int len = 0;
System.out.println("正在接收文件....");
while ((len = in.read(bs)) != -1) {
fos.write(bs, 0, len);
}
System.out.println("文件接收完毕...");
// 5.获取输出流
OutputStream out = client.getOutputStream();
// 6.调用输出流的write方法
out.write("您的文件收到了".getBytes());
System.out.println("给客户端回复信息完毕..");
// 7.释放资源
out.close();
fos.close();
in.close();
client.close();
} catch (IOException ie) {
ie.printStackTrace();
System.out.println("客户端有异常");
}
}
}).start();
}
// server.close();
// System.out.println("服务器关闭!!");
}
}
5.模拟BS架构服务器(了解)
BS架构中,B是浏览器,替代客户端
public class BSServer {
public static void main(String[] args) throws IOException {
//1.创建服务器
ServerSocket server = new ServerSocket(8888);
//2.等待客户端(浏览器)
Socket browser = server.accept(); // 阻塞
//3.获取输入流
InputStream in = browser.getInputStream();
//4.读数据
// byte[] bs = new byte[1024];
// int len = in.read(bs);
// System.out.println(new String(bs, 0, len));
//4.只需要读第一行 第二部分中的信息
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = br.readLine();
String[] names = line.split(" ");
String filename = names[1].substring(1);
System.out.println("浏览器想要:"+filename);
//5.把浏览器想要的文件,读取出来,发送给浏览器
//获取输出流
OutputStream out = browser.getOutputStream();
FileInputStream fis = new FileInputStream(filename);
byte[] bs = new byte[1024];
int len = 0;
out.write("HTTP/1.1 200 OK\r\n".getBytes());
out.write("Content-Type:text/html\r\n".getBytes());
out.write("\r\n".getBytes());
while ((len = fis.read(bs)) != -1) {
out.write(bs, 0, len);
}
//5.释放资源
in.close();
browser.close();
server.close();
}
}
6.扩展:模拟服务器扩展_图片显示问题(了解)
a.服务器要永不停止
b.修改html添加图片
<html>
<head>
<title>黑马收费处</title>
</head>
<body>
请扫描以下二维码付款(打八折)<br/>
<img src="111.png" width="20%"/>
</body>
</html>
总结