网络编程|Junit单元测试|设计模式
网络编程
- 在网络通信协议下,不同计算机上运行的程序,可以进行数据传输
网络编程三要素
- IP地址
- 设备在网络中的地址,是唯一的标识
- 端口
- 应用程序在设备中唯一的标识
- 协议
- 数据在网络中传输的规则,常见的协议有UDP协议和TCP协议
IP地址
-
IP:全程“互联网协议地址”,也称IP地址。是分配给上网设备的数字标签、常见的IP分类为:ipv4和ipv6
-
InetAddress的使用
-
为了方便我们对IP地址的获取和操作,Java提供了一个类InetAddress供我们使用
-
InetAddress:此类表示Internet协议(IP)地址
方法名 说明 static InetAddress getByName(String host) 在给定主机名的情况下获取InetAddress类的对象 String getHostName() 获取此IP地址的主机名 String getHostAddress() 返回IP地址字符串(以文本表现形式)
-
端口
- 端口号:应用程序的唯一标识方式,用两个字节表示的整数值,它的取值范围是065535,其中01023之间的端口号用于一些知名的网络服务或者应用。我们自己使用1024以上的端口号就可以了
- 注意:一个端口号只能被一个应用程序使用
协议
- UDP协议
- 用户数据报协议(User Datagram Protocol)
- UDP是面向无连接通信协议。速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据
- TCP协议
- 传输控制协议(Transmission Control Protocol)
- TCP协议是面向连接的通信协议。速度慢,没有大小限制,数据安全
TCP通信程序
-
客户端程序:Socket
- 先找到计算机
- 再找到计算机上的服务端程序
- 按照TCP协议进行数据发送、接收
- 基于IO流实现
// 创建客户端Socket对象,并连接服务端程序 Socket socket = new Socket("对方计算机IP地址", "服务端程序端口号"); // 基于socket对象,获取网络输出流(发送数据) OutputStream netOut = socket.getOutputStream(); // 发送数据 netOut.write("数据".getBytes()); // 关闭资源 netOut.close(); socket.close();
-
服务端程序:ServerSocket
- 绑定服务端程序端口号
// 创建服务端Socket对象,并指定端口号 ServerSocket ss = new ServerSocket(9090); // 监听客户端连接,获取到一个Socket对象 Socket server = ss.accept(); // 接收数据 InputStream netIn = server.getInputStream(); byte[] buf = new byte[1024]; int len = netIn.read(buf);
练习
// 服务端代码 import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class TcpServer { public static void main(String[] args) throws IOException { ServerSocket ss = new ServerSocket(9999); System.out.println("服务器已启动。。。"); Socket accept = ss.accept(); System.out.println(accept.getInetAddress().getHostAddress() + "客户端已连接~"); InputStream netInput = accept.getInputStream(); byte[] buf = new byte[1024]; netInput.read(buf); String s = new String(buf, 0, buf.length); System.out.println(s); netInput.close(); ss.close(); } } // 客户端代码 import java.io.IOException; import java.io.OutputStream; import java.net.Socket; public class TcpClient { public static void main(String[] args) throws IOException { Socket client = new Socket("127.0.0.1", 9999); OutputStream netOutput = client.getOutputStream(); netOutput.write("你好".getBytes()); client.close(); } } /* 运行结果: 服务器已启动。。。 127.0.0.1客户端已连接~ 你好 */
案例
-
需求
- 客户端:将本地文件上传到服务器。接收服务器的反馈
- 服务端:接收客户端上传的文件,上传完毕后给出反馈
// 服务端代码 port java.io.*; import java.net.ServerSocket; import java.net.Socket; public class TCPServer { public static void main(String[] args) throws IOException { String to = "to/target.jpg"; ServerSocket ss = new ServerSocket(9999); System.out.println("服务端已启动。。。"); Socket server = ss.accept(); System.out.println(server.getInetAddress().getHostAddress() + "客户端已连接~"); InputStream netInput = server.getInputStream(); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(to)); int data = -1; while ((data = netInput.read()) != -1){ bos.write(data); } System.out.println("上传文件接收完毕"); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(server.getOutputStream())); bw.write("文件上传成功!"); bw.newLine(); bw.close(); bos.close(); netInput.close(); server.close(); } } /* 服务端已启动。。。 127.0.0.1客户端已连接~ 上传文件接收完毕 */ // 客户端代码 import java.io.*; import java.net.Socket; public class TCPClient { public static void main(String[] args) throws IOException { String from = "from/a.jpg"; Socket client = new Socket("127.0.0.1", 9999); BufferedInputStream bis = new BufferedInputStream(new FileInputStream(from)); OutputStream netOutput = client.getOutputStream(); System.out.println("文件正在上传中。。。"); int len = -1; while ((len = bis.read()) != -1){ netOutput.write(len); } client.shutdownOutput();//告知服务端文件发送完毕 BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream())); System.out.println(br.readLine()); br.close(); bis.close(); netOutput.close(); client.close(); } } /* 文件正在上传中。。。 文件上传成功! */
设计模式
单例设计模式
-
保证程序中运行的某个类只能创建一个对象(节省空间,共享数据)
-
实现步骤:
-
将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象
-
在该类内部产生一个唯一的实例化对象,并且将其封装为private static 类型的成员变量
-
定义一个静态方法返回这个唯一对象
-
-
单例设计模式的类型
-
饿汉单例设计模式:随着类的加载就把唯一对象创建完成
-
懒汉单例设计模式:当需要使用对象时才创建对象
-
多例设计模式
- 多例模式是一种常用的设计模式之一。通过多例模式可以保证项目中,应用该模式的类有固定数量的实例,多例类要自我创建并管理自己的实例,还要向外界提供获取本类实例的方法
- 实现步骤
- 创建一个类,将构造方法私有化,使其不能在类的外部通过new关键字实例化该类的对象
- 在类中定义该类被创建对象的总数量
- 在类中定义存放类实例的list集合
- 在类中提供静态代码块,在静态代码块中创建类的实例
- 提供获取类实例的静态方法
工厂设计模式
-
工厂模式时java中最常用的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,之前我们创建类对象时,都是使用new对象的形式创建,除new对象方式之外,工厂模式也可以创建对象
-
作用:解决了类与类之间的耦合问题
-
案例
// 汽车接口 public interface Car { public abstract void run(); } // 法拉利类 public class Falali implements Car{ @Override public void run() { System.out.println("法拉利"); } } // 奔驰类 public class Benchi implements Car{ @Override public void run() { System.out.println("奔驰"); } } // 汽车工厂类 public class CarFactory { private CarFactory(){} public static Car getInstance(String name){ Car car = null; if ("falali".equals(name)){ car = new Falali(); } else if ("benchi".equals(name)) { car = new Benchi(); } return car; } } // bean.properties配置文件 name = benchi // 测试类 import java.util.ResourceBundle; public class Test { public static void main(String[] args) { ResourceBundle rb = ResourceBundle.getBundle("Bean"); String name = rb.getString("name"); Car c = CarFactory.getInstance(name); c.run(); } }
Junit单元测试
- 单元测试就是编写测试代码,可以准确、快速的保证程序的正确性,Junit时java单元测试的框架
- JUnit4可以通过注解的方式来标记方法,让方法存在某种意义,常见的注解有:
- @BeforeClass // 全局只会执行一次,而且时第一个运行(标记的方法需要是一个静态无参无返回值的方法)
- @Before // 再测试方法运行之前运行(非静态无参无返回值方法)
- @Test // 测试方法(此方法必须是非静态无参无返回值方法),主要用于测试的方法
- @After // 在测试方法运行之后运行(非静态无参无返回值方法)
- @AfterClass // 全局只会执行一次,而且是最后一个运行(标记的方法需要是一个静态无参无返回值方法)
- @lgnore // 忽略此方法
断言的使用
// 第一个参数表示期望值
// 第二个参数表示实际值
// 如果实际值和期望值相同,说明结果正确就测试通过,如果不相同,说明结果是错误的,就会报错
Assert.assertEquals(期望值, 实际值);
Assert.assertEquals("异常原因", 期望值, 实际值);
// 例如
int result = add(100, 200);
Assert.assertEquals(300, result);