JavaSE预习Day4

网络编程

引入

基本的通信架构有2种形式:CS架构( Client客户端/Server服务端 ) 、 BS架构(Browser浏览器/Server服务端)(Browser浏览器不需要程序员开发实现。)。无论是CS架构,还是BS架构的软件都必须依赖网络编程!

网络通信三要素

IP

IP:设备在网络中的地址,
是唯一的标识。
IP地址有两种形式:IPv4(32bit,点分十进制表示法)、IPv6(128bit,分成8段表示,每段每四位编码成一个十六进制位表示, 数之间用冒号(:)分开)
IP域名–>IP(DNS服务器)
公网IP, 内网IP
 公网IP:是可以连接互联网的IP地址;内网IP:也叫局域网IP,只能组织机构内部使用。
 192.168. 开头的就是常见的局域网地址,范围即为192.168.0.0–192.168.255.255,专门为组织机构
内部使用。
特殊IP地址:
 127.0.0.1、localhost:代表本机IP,只会寻找当前所在的主
机。
IP常用命令:
 ipconfig:查看本机IP地址。
 ping IP地址:检查网络是否连通。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class InetAddressTest {
public static void main(String[] args) throws IOException {
//1.取本机IP,会以一个inetAddress的对象返回
InetAddress byAddress = InetAddress.getLocalHost();
System.out.println(byAddress.getHostName());//取该ip地址对象对应的主机名。
System.out.println(byAddress.getHostAddress());//获取该ip地址对象中的ip地址信息。
//2.指定ip地址或者域名,返回一个inetAddress对象
InetAddress byName = InetAddress.getByName("www.baidu.com");
System.out.println(byName.getHostName());
System.out.println(byName.getHostAddress());
//3.在指定毫秒内,判断主机与该ip对应的主机是否能连通
System.out.println(byName.isReachable(6000));
}
}

端口

端口:应用程序在设备中唯一的标识,标记正在计算机设备上运行的应用程序的,被规定为一个 16 位的二进制,范围是 065535。
分类
 周知端口:0
1023,被预先定义的知名应用占用(如:HTTP占用 80,FTP占用21)
 注册端口:1024~49151,分配给用户进程或某些应用程序。
 动态端口:49152到65535,之所以称为动态端口,是因为它 一般不固定分配某种进程,而是动态分配。
注意:我们自己开发的程序一般选择使用注册端口,且一个设备中不能出现两个程序的端口号一样,否则出
错。

协议

协议:连接和数据在网络中传输的规则。
Snipaste 2025 02 25 17 24 11
Snipaste 2025 02 25 17 25 45
Snipaste 2025 02 25 17 27 36

UDP通信

UDP通信快速入门

Snipaste 2025 02 25 17 55 06

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class Client {
/*
客户端实现步骤
① 创建DatagramSocket对象(客户端对象) 扔韭菜的人
② 创建DatagramPacket对象封装需要发送的数据(数据包对象) 韭菜
盘子
③ 使用DatagramSocket对象的send方法,传入DatagramPacket对象
开始抛出韭菜
④ 释放资源
*/
public static void main(String[] args) throws IOException {
//1.创建客户端对象(扔韭菜盒子的人)
DatagramSocket datagramSocket = new DatagramSocket();//创建客户端的Socket对象,系统会随机分配一个端口号。
//也可人为设置端口
//2.创建数据包对象封装要发出去的数据(韭菜盒子)
byte buf[]="一得阁拉米".getBytes();
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length,
InetAddress.getLocalHost(), 6666);
//3.正式发送
datagramSocket.send(datagramPacket);
System.out.println("客户端数据发送完毕");
datagramSocket.close();
}
}
public class Server {
/*
服务端实现步骤
① 创建DatagramSocket对象并指定端口(服务端对象) 接韭菜的人
② 创建DatagramPacket对象接收数据(数据包对象) 韭菜盘子
③ 使用DatagramSocket对象的receive方法,传入DatagramPacket对象
开始接收韭菜
④ 释放资源
*/
//先启动服务端
public static void main(String[] args) throws IOException {
System.out.println("服务端启动完毕");
//1.创建服务端对象(接住韭菜盒子的人)
DatagramSocket datagramSocket2 = new DatagramSocket(6666);//创建服务端的Socket对象,并指定端口号
//2.创建数据包对象接受数据(韭菜盒子)
byte buffer[]=new byte[1024*64];//64kb
DatagramPacket datagramPacket2 = new DatagramPacket(buffer, buffer.length);
//3.正式接收
datagramSocket2.receive(datagramPacket2);
System.out.println("服务端数据接受完毕");
int length=datagramPacket2.getLength();
String s = new String(buffer,0,length);
System.out.println(s);
//补充:找到客户端ip,名字和端口
System.out.println(datagramPacket2.getAddress().getHostName());
System.out.println(datagramPacket2.getAddress().getHostAddress());
System.out.println(datagramPacket2.getPort());
datagramSocket2.close();
}
}

UDP通信多发多收(多个客户端发)

Snipaste 2025 02 25 18 05 44
注:这样服务端不要人为设置端口。不然会冲突

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Client {
/*
客户端反复发送
*/
public static void main(String[] args) throws IOException {
DatagramSocket datagramSocket = new DatagramSocket();//创建客户端的Socket对象,系统会随机分配一个端口号。
//也可人为设置端口
Scanner sc=new Scanner(System.in);
while (true) {
String s = sc.nextLine();
byte buf[]=s.getBytes();
if(s.equals("exit")){
System.out.println("退出成功");
datagramSocket.close();
break;//跳出死循环
}
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length,
InetAddress.getLocalHost(), 6666);
//3.正式发送
datagramSocket.send(datagramPacket);
}
}
}
public class Server {
/*
服务端反复接收,不要关闭服务端
//先启动服务端
*/
public static void main(String[] args) throws IOException {
System.out.println("服务端启动完毕");
//1.创建服务端对象(接住韭菜盒子的人)
DatagramSocket datagramSocket2 = new DatagramSocket(6666);//创建服务端的Socket对象,并指定端口号
//2.创建数据包对象接受数据(韭菜盒子)
byte buffer[]=new byte[1024*64];//64kb
DatagramPacket datagramPacket2 = new DatagramPacket(buffer, buffer.length);
while (true) {
//3.正式接收
datagramSocket2.receive(datagramPacket2);
System.out.println("服务端数据接受完毕");
int length=datagramPacket2.getLength();
String s = new String(buffer,0,length);
System.out.println(s);
//补充:找到客户端ip,名字和端口
System.out.println(datagramPacket2.getAddress().getHostName());
System.out.println(datagramPacket2.getAddress().getHostAddress());
System.out.println(datagramPacket2.getPort());
System.out.println("-------");
}

}
}

TCP通信

TCP通信-快速入门

Snipaste 2025 02 25 19 39 11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import java.io.*;
import java.net.Socket;
/*
客户端实现步骤
① 创建客户端的Socket对象,请求与服务端的连接。
② 使用socket对象调用getOutputStream()方法得到字节输出流。
③ 使用字节输出流完成数据的发送。
④ 释放资源:关闭socket管道。
*/
public class Client {
//客户端开发
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1 ",8888);//1.根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket
OutputStream os= socket.getOutputStream();//2.字节输出流
DataOutputStream dos=new DataOutputStream(os);//3.高级流
dos.writeUTF("DelayNoMore");//4.开始写
dos.close();//管高级流低级流也会关
socket.close();
}
}
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
//服务端开发
/*
服务端实现步骤
① 创建ServerSocket对象,注册服务端端口。
② 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象。
③ 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收。
④ 释放资源:关闭socket管道
*/
public static void main(String[] args) throws IOException {
System.out.println("服务端启动完毕");
ServerSocket ss=new ServerSocket(8888);
Socket socket = ss.accept();//阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象
InputStream is = socket.getInputStream();
DataInputStream dis=new DataInputStream(is);
System.out.println(dis.readUTF());
//补充:找到客户端ip,名字和端口
System.out.println(socket.getInetAddress().getHostAddress());
System.out.println(socket.getInetAddress().getHostName());
System.out.println(socket.getPort());
dis.close();
ss.close();
}
}

TCP通信-多发多收

使用TCP通信实现:多发多收消息。
① 客户端使用死循环,让用户不断输入消息。
② 服务端也使用死循环,控制服务端收完消息,继续等待接收下一个消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class Client {
//客户端开发
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);//1.根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket
OutputStream os= socket.getOutputStream();//2.字节输出流
DataOutputStream dos=new DataOutputStream(os);//3.高级流
Scanner sc=new Scanner(System.in);
while (true) {
System.out.println("请发送:");
String s = sc.nextLine();
if(s.equals("exit")){
System.out.println("退出成功");
dos.close();
socket.close();
break;//跳出死循环
}
dos.writeUTF(s);//4.开始写
dos.flush();
}
dos.close();//管高级流低级流也会关
socket.close();
}
}
public class Server {
//服务端开发
public static void main(String[] args) throws IOException {
System.out.println("服务端启动完毕");
ServerSocket ss=new ServerSocket(8888);
Socket socket = ss.accept();//阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象
InputStream is = socket.getInputStream();
DataInputStream dis=new DataInputStream(is);
while (true) {
String s = null;//如果客户端关闭了服务端会报异常,直接捕获
try {
s = dis.readUTF();
} catch (IOException e) {
System.out.println(socket.getInetAddress().getHostName()+"离线了");
dis.close();
break;
}
System.out.println(s);
}
}
}

TCP通信-支持与多个客户端同时通信

目前我们开发的服务端程序,是否可以支持与多个客户端同时通信 ?
 不可以的。
 因为服务端现在只有一个主线程,只能处理一个客户端的消息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class Client {
//客户端开发
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);//1.根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket
OutputStream os= socket.getOutputStream();//2.字节输出流
DataOutputStream dos=new DataOutputStream(os);//3.高级流
Scanner sc=new Scanner(System.in);
while (true) {
System.out.println("请发送:");
String s = sc.nextLine();
if(s.equals("exit")){
System.out.println("退出成功");
dos.close();
socket.close();
break;//跳出死循环
}
dos.writeUTF(s);//4.开始写
dos.flush();
}
dos.close();//管高级流低级流也会关
socket.close();
}
}
public class Server {
//服务端开发
public static void main(String[] args) throws IOException {
System.out.println("服务端启动完毕");
ServerSocket ss=new ServerSocket(8888);
while (true) {
Socket socket = ss.accept();//阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象
System.out.println("有人上线了"+socket.getRemoteSocketAddress());
new MyThread(socket).start();
}
}
}
public class MyThread extends Thread{
private Socket socket;
public MyThread(Socket socket){
this.socket=socket;
}
@Override
public void run(){
try {
InputStream is = socket.getInputStream();
DataInputStream dis=new DataInputStream(is);
while (true) {
try {
System.out.println(dis.readUTF());
} catch (IOException e) {
System.out.println("有人下线了"+socket.getRemoteSocketAddress());
dis.close();
socket.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

TCP通信-综合案例1群聊

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
public class Client {
//客户端开发
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);//1.根据指定的服务器ip、端口号请求与服务端建立连接,连接通过,就获得了客户端socket
new MyClientThread(socket).start();// 创建一个独立的线程,负责随机从socket中接收服务端发送过来的消息。
OutputStream os= socket.getOutputStream();//2.字节输出流
DataOutputStream dos=new DataOutputStream(os);//3.高级流
Scanner sc=new Scanner(System.in);
while (true) {
System.out.println("请发送:");
String s = sc.nextLine();
if(s.equals("exit")){
System.out.println("退出成功");
dos.close();
socket.close();
break;//跳出死循环
}
dos.writeUTF(s);//4.开始写
dos.flush();
}
// dos.close();//管高级流低级流也会关
// socket.close();
}
}
public class MyClientThread extends Thread{
private Socket socket;
public MyClientThread(Socket socket) {
this.socket=socket;
}

@Override
public void run() {
try {
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);//接收服务端传回来的消息
while (true){
try {
String msg = dis.readUTF();
System.out.println(msg);
} catch (Exception e) {
System.out.println("自己下线了:" + socket.getRemoteSocketAddress());
dis.close();
socket.close();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Server {
public static List<Socket>list=new ArrayList<>();
//服务端开发
/*
服务端实现步骤
① 创建ServerSocket对象,注册服务端端口。
② 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象。
③ 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收。
④ 释放资源:关闭socket管道
*/
public static void main(String[] args) throws IOException {
System.out.println("服务端启动完毕");
ServerSocket ss=new ServerSocket(8888);
while (true) {
Socket socket = ss.accept();//阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象
list.add(socket);
System.out.println("有人上线了"+socket.getRemoteSocketAddress());
new MyServerThread(socket).start();
}
}
}
public class MyServerThread extends Thread{
private Socket socket;
public MyServerThread(Socket socket){
this.socket=socket;
}
@Override
public void run(){
try {
InputStream is = socket.getInputStream();
DataInputStream dis=new DataInputStream(is);
while (true) {
try {
String s=dis.readUTF();
System.out.println(s);
sendMsg(s);//把这个消息分发给全部客户端进行接收。
} catch (IOException e) {
System.out.println("有人下线了"+socket.getRemoteSocketAddress());
Server.list.remove(socket);
dis.close();
socket.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void sendMsg(String s) throws IOException {
for (Socket socket1 : Server.list) {
//OutputStream os= socket.getOutputStream();//这一行写错了,如果这样的话只有发送的客户端收到消息!
OutputStream os= socket1.getOutputStream();
DataOutputStream dos=new DataOutputStream(os);
dos.writeUTF(s);
dos.flush();
}
}
}

TCP通信-综合案例2 BS架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class Server {
public static List<Socket>list=new ArrayList<>();
//服务端开发
/*
服务端实现步骤
① 创建ServerSocket对象,注册服务端端口。
② 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象。
③ 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收。
④ 释放资源:关闭socket管道
*/
public static void main(String[] args) throws IOException {
System.out.println("服务端启动完毕");
ServerSocket ss=new ServerSocket(8888);
while (true) {
Socket socket = ss.accept();//阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象
list.add(socket);
System.out.println("有人上线了"+socket.getRemoteSocketAddress());
new MyServerThread(socket).start();
}
}
}
public class MyServerThread extends Thread{
private Socket socket;
public MyServerThread(Socket socket){
this.socket=socket;
}
@Override
public void run(){
try {
OutputStream os = socket.getOutputStream();
PrintStream ps=new PrintStream(os);
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); // 必须换行
ps.println("<div style='color:red;font-size:120px;text-align:center'>黑马程序员666<div>");
ps.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}

拓展:使用线程池来优化(而非多个线程,节省性能)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class Server {
public static List<Socket>list=new ArrayList<>();
//服务端开发
/*
服务端实现步骤
① 创建ServerSocket对象,注册服务端端口。
② 调用ServerSocket对象的accept()方法,等待客户端的连接,并得到Socket管道对象。
③ 通过Socket对象调用getInputStream()方法得到字节输入流、完成数据的接收。
④ 释放资源:关闭socket管道
*/
public static void main(String[] args) throws IOException {
ExecutorService ex=new ThreadPoolExecutor(32,32,0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(8),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());//实现类
System.out.println("服务端启动完毕");
ServerSocket ss=new ServerSocket(8888);
while (true) {
Socket socket = ss.accept();//阻塞等待客户端的连接请求,一旦与某个客户端成功连接,则返回服务端这边的Socket对象
list.add(socket);
System.out.println("有人上线了"+socket.getRemoteSocketAddress());
ex.execute(new MyServer(socket));
}
}
}
public class MyServer implements Runnable{
private Socket socket;
public MyServer(Socket socket){
this.socket=socket;
}
@Override
public void run(){
try {
OutputStream os = socket.getOutputStream();
PrintStream ps=new PrintStream(os);
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); // 必须换行
ps.println("<div style='color:red;font-size:120px;text-align:center'>黑马程序员666<div>");
ps.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}

}
}

Java高级

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/**
* 字符串工具类
*/
public class StringUtil {
public static void printNumber(String name){
if(name == null){
System.out.println(0);
return; // 停掉方法
}
System.out.println("名字长度是:" + name.length());
}

/**
* 求字符串的最大索引
*/
public static int getMaxIndex(String data){
if(data == null) {
return -1;
}
return data.length() - 1;
}


}
/*
Junit单元测试框架
 JUnit是使用Java语言实现的单元测试框架,它是第三方公司开源出来的,很多开发工具已经集成了Junit框架,比如
IDEA。
优点
 编写的测试代码很灵活,可以指某个测试方法执行测试,也支持一键完成自动化测试。
 不需要程序员去分析测试的结果,会自动生成测试报告出来。
 提供了更强大的测试能力。
*/
/*
Junit单元测试-快速入门
 某个系统,有多个业务方法,请使用Junit框架完成对这些方法的单元测试。
 具体步骤
① 将Junit框架的jar包导入到项目中(注意:IDEA集成了Junit框架,不需要我们自己手工导入了)
② 编写测试类、测试类方法(注意:测试方法必须是公共的,无参数,无返回值的非静态方法)
③ 必须在测试方法上使用@Test注解(标注该方法是一个测试方法)
④ 在测试方法中,编写程序调用被测试的方法即可。
⑤ 选中测试方法,右键选择“JUnit运行” ,如果测试通过则是绿色;如果测试失败,则是红色
*/

/*只有一个通信管道的话就用带class的
开始执行的方法:初始化资源。
执行完之后的方法:释放资源。
*/
public class UtilTest {
@BeforeClass
public static void test11(){
System.out.println("test11BeforeClass执行了");
}
@Before
public void test1(){
System.out.println("test1Before执行了");
}
@After
public void test2(){
System.out.println("test2After执行了");
}
@AfterClass
public static void test22(){
System.out.println("test22AfterClass执行了");
}
@Test
public void TestPrintNumber(){
StringUtil.printNumber(null);
}
@Test
public void TestGetMaxIndex(){
int index = StringUtil.getMaxIndex("hihi");
System.out.println(index);
//断言机制
Assert.assertEquals("还是有误",3,index);//消息,预测,实际
}
}

反射

1

注解

1

动态代理

1