HTML

一、超文本标记语言

  1. HTML:Hyper Text Markup Language 超文本标记语言
  2. 标记语言:通过一组标签<关键字>

二、HTML语法规范

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html>
//头部head---浏览器的名字
<head>
<meta charset="utf-8">//默认字体
<title>H5的练习</title>
</head>
//内部body---浏览器内显示内容
<body>
<p>床前明月光</p>//p为其中一个
<p>疑是地上霜</p>
<p>举头望明月</p>
<p>低头思故乡</p>
</body>
</html>

三、各种标签学习(只展示body内部代码)

总结:

  • 段落基础标签

    hr      水平线

br      换行
p      分段(成对出现)
h1-h6
   分级标签(成对出现)
font     变颜色(成对出现)
b/strong(有语气)  加粗(成对出现)
i/em        斜体(成对出现)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	<h3>寒假社会实践</h3>

<!--水平线hr-->
<hr>

<!--分段p-->
<P>为更好地推动青年志愿服务参与乡村振兴,按照中央文明办<font color="red">“圆梦工程”</font>——农村未成年人思想道德建设志愿服务行动总体部署,团中央青年志愿者行动指导中心、中国青年志愿者协会拟继续支持基层团组织实施“助力乡村学校少年宫建设”志愿服务项目。</P>

<!--加粗b/strong(加语气) 斜体i/em-->
<P><b><i>“助力乡村学校少年宫建设”</i></b>志愿服务项目是“关爱行动”和“圆梦工程”的子项目,由团中央青年志愿者行动指导中心、中国青年志愿者协会共同组织实施。主要内容是组织、动员基层志愿服务组织,与文体师资力量不够的“乡村学校少年宫”所在农村学校建立长期结对关系,围绕课外活动、素质拓展、安全自护、思想引导、心理辅导等内容,定期选派青年志愿者配合学校开展志愿服务活动,助力“乡村学校少年宫”建设。</P>

<P>拟从中西部18个省(自治区、直辖市)、新疆生产建设兵团中遴选、支持50个左右的贫困地区县级团委或地市级、县级青年志愿者协会,共覆盖250所学校示范实施“助力乡村学校少年宫建设”志愿服务项目。</P>

<P>相关省级团委青年志愿者工作机构要高度重视,精心组织,结合辖区内现有乡村学校少年宫分布和当地志愿服务团队等情况,做好相关申报工作,遴选、指导申报地填写《2019-2020年度“助力乡村学校少年宫建设”志愿服务项目基层团组织申报表》(附件1),于2020年2月10日前将经审核的申报表统一发送至工作邮箱zyzgzb_2@163.com。</P>

代码结果如下:


  • 网站图片标签

img src 指定图片路径

  1.width 宽度
  2.heigth 高度
  3.alt 文件加载失败时的提示信息

`<img src="../img/10.jpg"  width="200px"  heigth="200px" alt="这张图片可能加载有问题"/>`
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

<!--
常用属性:
src:指定图片路径
width:宽度
heigth:高度
alt:文件加载失败时候的提示信息
-->

<!--
路径寻找问题:
./ 当前路径
../ 上一级路径
../../ 上上一级路径
-->
<img src="../img/10.jpg" width="200px" alt="这张图片可能加载有问题"/>

  • 链接标签

    ul  无序列表

  1.li 一行
  2.type 是哪种小图标disc(实心圆)/square(正方形)/circle(空心圆)

ol  有序列表

  1.type(属性) —1/a/i/I
  2.start(属性) —哪类型从哪个开始

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

<!--无序列表 ul
1. li(标签) ---列
2. type(属性) --- disc(实心圆)/square(正方形)/circle(空心圆)
-->
<ul type="square">
<!--一列 li -->
<li>百度</li>
<li>新浪微博</li>
<li>黑马程序员</li>
</ul>

<hr><!--下划线-->

<!--有序列表 ol
1.type(属性) ---1/a/i/I
2.start(属性) ---哪类型从哪个开始
                     -->
<ol type="1" start="2">
<!--一列 li -->
<li>百度</li>
<li>新浪微博</li>
<li>黑马程序员</li>
</ol>

代码结果如下:

href 超链接标签a

 1.href:指定跳转的链接地址  http协议(别人的)/文件路径(自己的)
 2.target:用什么形式打开     当前窗口(_self)/新建窗口(_blank)

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<!--无序列表-->
<ul type="circle">
<!--
超链接标签 a
1.href(属性):指定要跳转去的链接地址 需要加上http协议(别人的)/文件路径(自己的)
2.target:用什么形式打开
2.1: _self 当前窗口(默认)
2.2: _blank 新开一个窗口
-->
<li><a href="https://www.baidu.com/" target="_blank">百度</li>
<li><a href="https://www.bilibili.com/">哔哩哔哩</li>
<li><a href="http://dasai.lanqiao.cn/">蓝桥杯</li>
</ul>

  • 表格标签

    table 生成表格

tr
td

  1.border:边框(表格有边框)
  2.width:宽度
  3.height:高度
  4.bgcolor:背景色(tr td也可以用)
  5.align:对齐方式(tr td也可以用)

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

<!--
表格:table
常用属性:
1.border:边框
2.width:宽度
3.height:高度
4.bgcolor:背景色(tr td也可以用)
5.align:对齐方式(tr td也可以用)
1.tr: 行
2.td: 列
-->
<table border="3px" width="400px" height="100px" bgcolor="crimson" >
<!--第一行-->
<tr bgcolor="blank">
<td>1</td>
<td bgcolor="black">2</td> <!--2的这一个为黑色-->
<td>3</td>
<td>4</td>
<td>5</td>
</tr>

<!--第二行-->
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>

<!--第三行-->
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>

<!--第四行-->
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>

<!--第五行-->
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
<td>5</td>
</tr>

</table>

代码结果如下

表格合并问题:
  1.colspan 跨行
  2.rowspan 跨列
  3.嵌套时候是在一个框框内加一个表格

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
<!--
表格:table
1.colspan 跨行<tr>
2.rowspan 跨列<td>
-->

<table border="1px" width="400px">
<!--第一行-->
<tr>
<td colspan="2">11</td>
<td>13</td>
<td>14</td>
<td>15</td>
</tr>
<!--第二行-->
<tr>
<td>21</td>
<td>22</td>
<td>23</td>
<td>24</td>
<td>25</td>
</tr>
<!--第三行-->
<tr>
<td>31</td>
<td>32</td>
<td rowspan="2" colspan="2" align="center">
<!--嵌套表格-->
<table border="1px" width="100%" height="100%">
<tr>
<td> <img src="../../img/10.jpg" width="46px"/></td>
</tr>
</table>
</td>
<td>35</td>
</tr>
<!--第四行-->
<tr>
<td rowspan="2">41</td>
<td>42</td>
<td>45</td>
</tr>
<!--第五行-->
<tr>
<td>52</td>
<td>53</td>
<td>54</td>
<td>55</td>
</tr>
</table>

代码结果如下


反射

一、反射
  动态获取信息以及动态调用对象的方法的功能。能够对任意一个类,获取类的所有属性和方法

  • 解剖类—–>获取字节码文件对象

三种获取字节码对象方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package 反射联系;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
//1. Class的方法forName
Class clazz1=Class.forName("反射联系.Main"); //需要包.类名
//2. 为类的静态方法
Class clazz2=Main.class;
//3. 创建对象调用方法getClass方法
Main m=new Main();
Class clazz3=m.getClass();
System.out.println(clazz1==clazz2);//判断三个是不是相等
System.out.println(clazz3==clazz2);
//结果都是true
}
}

  • 反射(Class.forName(“包.类名”))

榨汁机榨汁的案例
分别有 水果(Fruit) 苹果(Apple) 香蕉(Banana) 桔子(Orange) 榨汁(squeeze)

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
public class Main {
public static void main(String[] args) throws Exception {
Juicer j=new Juicer();//购买榨汁机
j.run(new Apple()); //榨汁机炸苹果
//j.run(new Orange()x);//Apple a=new Orange(); 类型不匹配
j.run(new Orange());
}
}

class Apple {
public void squeeze() {
System.out.println("榨出苹果汁儿");
}
}

class Orange {
public void squeeze() {
System.out.println("榨出橘子汁儿");
}
}
//榨汁机负责榨水果
class Juicer{
public void run(Apple a)//榨苹果
{
a.squeeze();
}

public void run(Orange o)//榨橘子
{
o.squeeze();
}
}

  但是这种问题就是如果有很多水果就不停的要建立水果类,然后不停的在Juicer类中写出榨水果的run方法比较麻烦,所以我们要考虑使用多态的方法Fruit实现squeeze()榨汁。

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
public class Main {
public static void main(String[] args) throws Exception {
Fruit f=new Apple();//多态 -----左父右子
f.squeeze();
}
}

interface Fruit{ //实现榨汁
public void squeeze();
}


class Apple implements Fruit{//所有要用的类实现接口Fruit

public void squeeze() {
System.out.println("榨出苹果汁儿");
}
}

class Orange implements Fruit{
public void squeeze() {
System.out.println("榨出橘子汁儿");
}
}

class Juicer{
public void run(Fruit f)//run对象为接口的 f
{
f.squeeze();
}
}

而使用反射
主要是添加一个文件名为config.properties(里面写包名.你需要的实现的类名)

1
2
3
4
5
6
7
8
9
10
11
12

public class Main {
public static void main(String[] args) throws Exception {
//使用反射配置文件
BufferedReader br=new BufferedReader(new FileReader("config.properties"));//字符流
Class c=Class.forName(br.readLine()); //读取一行(\u53CD\u5C04\u8054\u7CFB.Apple)
Fruit f=(Fruit)c.newInstance(); //---父类引用指向子类对象
//建立榨汁机对象然后调用run方法run(f)
Juicer j=new Juicer();
j.run(f);//执行结果为 榨出苹果汁
}
}

  • 通过反射—>带参构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package 反射联系;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Main2 {
public static void main(String[] args) throws Exception{
Class clazz=Class.forName("反射联系.Main");//拿到字节码
//无参构造创建对象
Main m=(Main) clazz.newInstance();
System.out.println(m);

Constructor c=clazz.getConstructor(Fruit.class);//获取有参构造
Main m1=(Main) c.newInstance("Apple");//有参构造创建对象
System.out.println(m1);
}
}

  • 通过反射成员变量(私有/共有)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.lang.reflect.Constructor;
public class Main2 {
public static void main(String[] args) throws Exception{
Class clazz=Class.forName("反射联系.Main");//拿到字节码
Constructor c=clazz.getConstructor(String.class);//获取有参构造getConstructor
Main m1=(Main) c.newInstance("Apple");//有参构造创建对象

//1 共有的public
java.lang.reflect.Field f1=clazz.getField("Fruit");//获取姓名字段------getField
f1.set(m1,"Orange");//将苹果apple改成orange

//2.私有的private
java.lang.reflect.Field f2=clazz.getDeclaredField("Fruit");//暴力反射获取姓名字段-----getDeclaredField
f2.setAccessible(true); //去除私有private权限
f2.set(m1,"Orange");//将苹果apple改成orange
}
}

  • 通过反射方法(有参/无参)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class Main3 {
public static void main(String[] args) throws Exception{
Class clazz=Class.forName("反射联系.Main");//拿到字节码
Constructor c=clazz.getConstructor(String.class);//获取有参构造getConstructor
Main m1=(Main) c.newInstance("Apple");//有参构造创建对象

//无参方法
Method m3=clazz.getMethod("squeeze");
m3.invoke(m3);

//有参方法
Method m2=clazz.getMethod("squeeze",int.class);
m2.invoke(m2);

}
}

二、越过泛型检查
  泛型只在编译期间有效,运行期(字节码文件)会被擦除掉。

1
2
3
4
5
6
7
8
9
10
11
12
13
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Main4 {
public static void main(String[] args) throws Exception{
ArrayList<Integer> l=new ArrayList<Integer>();
l.add(111);
l.add(222);
Class c=Class.forName("java.util.ArrayList"); //拿到字节码文件
Method m=c.getMethod("add",Object.class); //更改add方法
m.invoke(l,"abc");调用Method方法的invoke修改方法添加add
System.out.println(l); //------>[111, 222, abc]
}
}

三、指定值(setProperty)
  public void setProperty(Object o,String qian,Object hou):把o对象中名字是qian的属性值—>改成hou

稀疏数组

稀疏sparsearray数组

  • 适用前提:大部分元素为0/是同一个值的数组。
  • 处理方法:
    • 第一行记录数组(几行+几列+几个不同值)
    • 依次列出不同值元素(所在行+所在列+值)

稀疏数组举例:


二维数组与稀疏数组转换

  1. 遍历二维数组–>有效数据的个数sum
  2. 根据sum可以创建稀疏数组sparseArr int[sum+1]3
  3. 二维数组有效数据存到稀疏数组

转换代码:

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
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int[][] a=new int[11][11];//原始数组为11*11的矩阵
a[1][2]=1;//数组里面的第二行第三列数字为1
a[2][3]=2;//数组里面的第三行第四列数字为2
System.out.println("原始数据:");
for(int i=0;i<a.length;i++)
{
for(int j=0;j<a[i].length;j++)
{
System.out.printf("%d\t",a[i][j]);
}
System.out.println();
}

//二维数组a-----稀疏数组b
int sum=0;//记录一共多少个非0数
for(int i=0;i<a.length;i++)
{
for(int j=0;j<a[i].length;j++)
{
if(a[i][j]!=0)//非0的情况就加一
{
sum++;//记录一共有多少非0数
}
}
}
System.out.println("一共有"+sum+"个非0数字");
int[][] b=new int[sum+1][3];//sum行列每一个行列值 每个数都是三列元素
b[0][0]=11;//第一行放数组的行+列+sum
b[0][1]=11;
b[0][2]=sum;
int flag=1;//下标变换存数
for(int i=0;i<a.length;i++)
{
for(int j=0;j<a[i].length;j++)
{
if(a[i][j]!=0)
{

b[flag][0]=i;
b[flag][1]=j;
b[flag][2]=a[i][j];
flag++;//只能等这一行放入了再flag++
}
}
}
//输出稀疏数组
System.out.println("稀疏数组:");
for(int i=0;i<sum+1;i++)
{
for(int j=0;j<3;j++)
{
System.out.printf("%d\t",b[i][j]);
}
System.out.println();
}

//稀疏数组b-----二维数组c
int[][] c=new int[b[0][0]][b[0][1]];
int flag1=1;
for(int i=1;i<b.length;i++)
{
c[b[i][0]][b[i][1]]=b[i][2];
}
//输出c数组
System.out.println("输出原数组:");
for(int i=0;i<c.length;i++)
{
for(int j=0;j<c[i].length;j++)
{
System.out.printf("%d\t",c[i][j]);
}
System.out.println();
}
}
}

#

网络课设

一、题目和要求
题目:协议分析软件开发及网络协议分析
(1)教学内容
网络协议分层结构,网络协议工作过程,协议数据单元结构,协议分析,协议设计,协议分析软件开发。
(2)教学要求
理解网络协议的层次结构及网络协议的工作过程,掌握网络协议的分析方法及网络协议的设计与应用。


二、了解必须的协议首部格式

  • IP协议(首部格式):

IP协议,又译为网际协议或互联网协议,是用在TCP/IP协议簇中的网络层协议。IP协议位于TCP/IP协议的网络层,位于同一层次的协议还有下面的ARP和RARP以及上面的ICMP(Internet控制报文协议)和IGMP(Internet组管理协议)。除了ARP和RARP报文以外的几乎所有的数据都要经过IP协议进行传送。ARP和RARP报文没有封装在IP数据报中,而ICMP和IGMP的数据则要封装在IP数据报中进行传输。由于IP协议在网络层中具有重要的地位,TCP/IP协议的网络层又被称为IP层。

  • TCP协议(首部格式):

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。
TCP旨在适应支持多网络应用的分层协议层次结构。 连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。TCP假设它可以从较低级别的协议获得简单的,可能不可靠的数据报服务。 原则上,TCP应该能够在从硬线连接到分组交换或电路交换网络的各种通信系统之上操作。
当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据流分割成适当长度的报文段,最大传输段大小(MSS)通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)限制。之后TCP把数据包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。

  • UDP协议(首部格式):

  UDP协议概述:一种无连接协议,提供无连接服务,在传送数据之前不需要先建立连接;传送的数据单位协议是 UDP 报文或用户数据报。对方的运输层在收到 UDP 报文后,不需要给出任何确认。虽然 UDP 不提供可靠交付,但在某些情况下 UDP 是一种最有效的工作方式。UDP 用户数据报是在运输层的端到端抽象的逻辑信道中传送的。


三、实现思路

  1. JAVA语言虽然在TCP/UDP传输方面给予了良好的定义,但对于网络层以下的控制,却是无能为力的。JPCAP扩展包弥补了这一点,jPcap是一个可以让java工作在链路层的类库;当然,它底层还是使用了本机API通过Jini调用,在javaAPI中得到数据。JPCAP实际上并非一个真正去实现对数据链路层的控制,而是一个中间件,JPCAP调用wincap/libpcap,而给JAVA语言提供一个公共的接口,从而实现了平台无关性。
  2. 通过使用主函数main去调用分析函数analyzePacke()和其他的方法去解决各个功能。通过while循环不断的输入选项去完成选择。通过线程抓获去获取数据包(用数组去存放数据包),然后重写run()方法去获取数据包。
  3. 最后可以通过break跳出menu菜单(或者选择停止抓数据包)。

四、具体实现代码

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
import jpcap.*;
import jpcap.packet.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;

public class Test{
//定义默认最大抓包数
private static final int max = 1000;
//显示所有网络设备信息
private static void showDeviceList(NetworkInterface[] devices) {
//展示当前主机设备信息
System.out.println("本机上所有适配器如下:");
for (int i = 0; i < devices.length; i++)
{
//网络适配器名称(循环输出所有的适配器)
System.out.println("Adapter " + (i + 1) + "(名称)" + devices[i].description);

//MAC地址
System.out.print(" MAC address(MAC地址): ");
for (byte b : devices[i].mac_address) //用:隔开输出16进制
{
System.out.print(Integer.toHexString(b & 0xff) + ":");
}
System.out.println();

//IP地址
for (NetworkInterfaceAddress a : devices[i].addresses) //调用方法输IP地址
{
System.out.println(" IPv6/IPv4 address(IP地址): " + a.address);
}
System.out.println();
}
}

//网络接口监听
private static JpcapCaptor openDevice(NetworkInterface[] devices, int choice) throws java.io.IOException //抛出异常
{
JpcapCaptor captor = null;
Try
{
captor = JpcapCaptor.openDevice(devices[choice], 65535, false, 3000);
//方法中的变量为一次性抓65535的长度,超时时间为3000ms
}
catch (IOException e)
{
e.printStackTrace();//打印异常信息在程序中出错的位置以及原因
System.out.println("打开网络接口失败!");
}
return captor;
}

//数据包捕获线程(Thread)
private static class AThread implements Runnable
{
Thread thread;
JpcapCaptor captor;
Packet[] packet;

//线程中断标志
volatile boolean cancel;
AThread(JpcapCaptor captor) throws IOException{
this.captor = captor;//用this调用数据
this.packet = new Packet[max];//用this调用数据
this.cancel = false;//用this调用数据
thread = new Thread(this);//用this调用数据
}

@Override //重写线程中的run方法
public void run() {
packet = new Packet[max];
for(int i = 0; i < max && cancel == false; i++){
packet[i] = captor.getPacket();//调用getpacket()方法获取数据包
}
}
//设置中断的方法(主要用于选项2的操作)
public void cancel()
{
cancel = true;
}

public Packet[] getPacket()
{
return packet;//获取数据包
}

}



private static Packet[] readPacket(JpcapCaptor captor, String filename)
{
Packet[] packet = new Packet[max];//定义一个packet数组去存取数据包
try
{
captor = JpcapCaptor.openFile(filename);
}
catch (IOException e)
{
e.printStackTrace();
}

for(int i = 0;;i++){
packet[i] = captor.getPacket();
if(packet[i] == null)
break;
}
return packet;
}

//按键5的功能去实现展示当前有多少数据包
private static void analyzePacket(Packet[] packet)
{
//定义三个泛型去动态存取数据包个数
ArrayList<UDPPacket> udpPacketArray = new ArrayList<UDPPacket>();
ArrayList<ARPPacket> arpPacketArray = new ArrayList<ARPPacket>();
ArrayList<TCPPacket> tcpPacketArray = new ArrayList<TCPPacket>();
int count, count1, count2, count3,;
count = count1 = count2 = count3 = 0;
for(int i = 0; packet[i] != null && i < max; i++) //循环存各个类型的
{
count++;
if (packet[i] instanceof UDPPacket)//如果获取的数据包属于UDPPacket包
{
UDPPacket udp = (UDPPacket) packet[i];
udpPacketArray.add(udp);
count1++;
}
else
if(packet[i] instanceof ARPPacket)//如果获取的数据包属于ARPPacket包
{
ARPPacket arp = (ARPPacket) packet[i];
arpPacketArray.add(arp);
count2++;
}
else
if(packet[i] instanceof TCPPacket)//如果获取的数据包属于TCPPacket包 {
TCPPacket tcp = (TCPPacket) packet[i];
tcpPacketArray.add(tcp);
count3++;
}
}
System.out.println();//换行方便查看
System.out.println("所有数据包数:" + count);
System.out.println("UDP数据包数:" + count1);
System.out.println("ARP数据包数:" + count2);
System.out.println("TCP数据包数:" + count3);
}

//此方法循环输出每个包的信息
private static void showPacket(Packet[] packet)
{
for(int i = 0; packet[i] != null && i < max-1; i++)
{
System.out.println("Packet " + (i+1) + " : " + packet[i]);
}
}

//按键4显示数据包详细情况
private static void showPacketDetail(Packet[] packet)
{
System.out.print("输入你想查看的包序号");
Scanner input=new Scanner(System.in);
int num=input.nextInt();//输入你要选择看的包序号
num=num-1;
for(int i = 0; packet[i] != null && i < max-1; i++)
{
if(i==num) //如果选的那个数字和循环的符合的话去判断是哪个数据包
{
if(packet[i] instanceof UDPPacket) // 如果获取的数据包属于UDPPacket包
{
UDPPacket udp = (UDPPacket) packet[i];
HexBinaryAdapter head = new HexBinaryAdapter();
String str = head.marshal(udp.header);
int tou = (str.charAt(29)-48)*4*2;//主要用于判断推送字节输出检验和
System.out.println("Packet " + (i+1) + " : UDP" );
System.out.println(" 数据 : " + str);
System.out.println("**********ip首部*********");
System.out.println(" 版本:IPv"+ udp.version);
System.out.println(" 首部长度:" + str.substring(29,30));
System.out.println(" 区分服务: 0");
System.out.println(" 总长度:" + udp.length);
System.out.println(" 标识:" + udp.ident);
System.out.println(" MF: " + udp.more_frag);
System.out.println(" DF: " + udp.dont_frag);
System.out.println(" 片偏移:" + udp.offset);
System.out.println(" 生存时间:" + udp.hop_limit);
System.out.println(" 源 ip地址 : " + udp.src_ip.toString());
System.out.println(" 目的ip地址 : " + udp.dst_ip.toString());
System.out.println("**********数据部分*********");
System.out.println(" 源端口 : " + String.valueOf(udp.src_port));
System.out.println(" 目的端口 : " + String.valueOf(udp.dst_port));
System.out.println(" 长度 : " + String.valueOf(udp.length));
System.out.println(" 校验和 : +str.substring(28+tou+12,28+tou+16));
System.out.println();
}
else
if(packet[i] instanceof TCPPacket) //如果获取的数据包属于TCPPacket包
{
TCPPacket tcp = (TCPPacket) packet[i];//TCP
HexBinaryAdapter head = new HexBinaryAdapter();//转成16进制
String str = head.marshal(tcp.header);
int tou = (str.charAt(29)-48)*4*2;//主要用于判断推送字节输出检验和
System.out.println("Packet " + (i+1) + " : TCP" );
System.out.println(" 数据 : " + str);
System.out.println("**********ip首部*********");
System.out.println(" 版本:IPv"+ tcp.version);
System.out.println(" 首部长度:" + str.substring(29,30));
System.out.println(" 区分服务: 0");
System.out.println(" 总长度:" + tcp.length);
System.out.println(" 标识:" + tcp.ident);
System.out.println(" MF: " + tcp.more_frag);
System.out.println(" DF: " + tcp.dont_frag);
System.out.println(" 片偏移:" + tcp.offset);
System.out.println(" 生存时间:" + tcp.hop_limit);
System.out.println(" 源 ip地址 : " + tcp.src_ip.toString());
System.out.println(" 目的ip地址 : " + tcp.dst_ip.toString());
System.out.println("**********数据部分*********");
System.out.println(" 源 ip地址 : " + tcp.src_ip.toString());
System.out.println(" 目的ip地址 : " + tcp.dst_ip.toString());
System.out.println(" 源端口 : " + String.valueOf(tcp.src_port));
System.out.println(" 目的端口 : " + String.valueOf(tcp.dst_port));
System.out.println(" 序号:" + tcp.sequence);
System.out.println(" 确认号:" + tcp.ack_num);
System.out.println(" 数据偏移:" + tcp.offset);
System.out.println(" 保留:0");
System.out.println(" 紧急URG:" + tcp.urg);
System.out.println(" 确认ACK:" + tcp.ack);
System.out.println(" 推送PSH:" + tcp.psh);
System.out.println(" 复位RST:" + tcp.rst);
System.out.println(" 同步SYN:" + tcp.syn);
System.out.println(" 终止FIN:" + tcp.fin);
System.out.println(" 窗口:" + tcp.window);
System.out.println(" 检验和:" + str.substring(28+tou+32,28+tou+36));
System.out.println(" 紧急指针:" + tcp.urgent_pointer);
System.out.println(" 选项:" + tcp.option);
System.out.println();
}
else
if(packet[i] instanceof ARPPacket)//如果获取的数据包属于ARPPacket包
{
ARPPacket arp = (ARPPacket) packet[i];//ARP
HexBinaryAdapter head = new HexBinaryAdapter();//转成16进制
String str = head.marshal(arp.header);
byte[] b = new byte[4];
String s1 = "";
String s2 = "";
b = arp.target_protoaddr;
s1 += String.valueOf((b[0] & 0xff) + "." + ( b[1] & 0xff) + "." + (b[2] & 0xff) + "." + (b[3] & 0xff));
b = arp.sender_protoaddr;
s2 += String.valueOf((b[0] & 0xff) + "." + ( b[1] & 0xff) + "." + (b[2] & 0xff) + "." + (b[3] & 0xff));
for (byte d : arp.sender_hardaddr)
{
System.out.print(Integer.toHexString(d & 0xff) + ":");
}
for (byte e : arp.target_hardaddr)
{
System.out.print(Integer.toHexString(e & 0xff) + ":");
}
System.out.println("Packet " + (i+1) + " : ARP" );
System.out.println(" 数据 : " + str);
System.out.println(" Hardware type: " + arp.hardtype);
System.out.println(" protocol type : " + arp.prototype);
System.out.println(" Hardware size : " + arp.hlen);
System.out.println(" protocol size : " + arp.plen);
System.out.print(" sender MAC address: ");
for (byte d : arp.sender_hardaddr)
{
System.out.print(Integer.toHexString(d & 0xff) + ":");
}
System.out.println();
System.out.println(" sender ip address: " + s2);
System.out.print(" target MAC address: " );
for (byte e : arp.target_hardaddr)
{
System.out.print(Integer.toHexString(e & 0xff) + ":");
}
System.out.println();
System.out.println(" target ip address: " + s1);

System.out.println();
}
}
}
}


public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
//数组存放数据包
Packet[] packet = new Packet[max];
//初始化数据包捕获的线程
AThread t = null;
//获取网络设备并显示
NetworkInterface[] devices = JpcapCaptor.getDeviceList();
showDeviceList(devices);
//输入选择的监控的网卡
System.out.print("选择需要监听的设备序号:");
int card = scanner.nextInt();
card = card -1;
System.out.println();

//打开选择的网络接口
JpcapCaptor captor = openDevice(devices, card);

menu:
while(true) {
//功能菜单
System.out.println("选择功能编号:");
System.out.println("1. 捕获当前网卡的数据包");
System.out.println("2. 停止捕获网络数据包");
System.out.println("3. 显示当前捕获的数据包");
System.out.println("4. 查看数据包详细信息");
System.out.println("5. 分析数据包的协议分布");
System.out.println("6. 退出!");
System.out.print("你的选择:");
//用户选择
int choice = scanner.nextInt();//输入选择项

//功能执行(通过选各个类型去决定下一步干什么)
switch (choice){
case 1: System.out.println("正在捕获数据包...");//选择去抓包抓数据包
t = new AThread(captor);
Thread capThread = new Thread(t);
capThread.start();
break;
case 2: System.out.println("已停止捕获数据包");//停止抓数据包
t.cancel();//调用停止方法cancel将布尔值的中断标志改为false
break;
case 3: System.out.println("显示当前捕获的数据包如下:");//如果线程为空那就显示失败
if(t == null)
{
System.out.println("数据包捕获未开启,失败!");
break;
}
packet = t.getPacket(); //调用获得数据包的方法
showPacket(packet);//调用展示数据包的方法
break;
case 4: System.out.println("数据包详细分析:");//调用展示数据包细节的方法
showPacketDetail(packet);
break;
case 5: System.out.println("数据包的协议分布如下:");
analyzePacket(packet);//调用分析数据包的方法
break;
case 6: System.out.println("退出!");//想要结束就break跳出menu
break menu;
}
System.out.println();//分隔一行为了方便查看
}

//关闭线程和抓包
captor.close();
}
}

五设计中的问题以及心得

  1. 一开始不知道怎么去抓获数据包就去上网搜查和查看数据最终发现可以使用JPCAP扩展,jPcap是一个可以让java工作在链路层的类库调用wincap/libpcap,而给JAVA语言提供一个公共的接口,从而使用插件最终得到抓获数据包的操作。
  2. 第一步讨论得到后,与组员讨论最终决定使用主函数调用每个功能模块,既使用模块化设计方法得到功能。但是不知道怎么去抓获数据包之后存储,询问其他同学和查看网络API之后发现可以通过数组去存储数据包,从而用循环去不断的操作。
  3. 可以在抓取和实现功能后,发现还需要界面设计达到分析协议软件开发,或者通过GUI图形界面显示。
  4. 我和组员分工之后,我主要去实现主函数和TCP协议的分析部分,主要是和组员的代码要能配对起来比较麻烦,最终不断地调试和改bug得到了结果。
  5. 抓获数据包最终分析的时候,首部其他内容都可以得到调用方法得到结果,但是TCP和IP检验和部分就比较麻烦,我们最终决定使用推算字节数得到答案。
    以IP检验和为例:
    创建一个 HexBinaryAdapter的对象将二进制数组转换为十六进制字符串:
1
HexBinaryAdapter head =  new HexBinaryAdapter();

定义一个字符串存首部长度head的16进制信息:

1
String str = head.marshal(udp.header);

计算IP首部部分的长度:

1
2
3
4
5
6
7
8
	int tou = (str.charAt(29)-48)*4*2;
```
因为IP之前的MAC帧就有14个字节,而一个字节就是2位十六进制,然后通过减去0的ASCII码转换成相对应的16进制数字。
而为了获得检验和就需要转字节之后加上之前的12个字节,从13到16就是Ip数据包的检验和部分
System.out.println(" 校验和 : " +str.substring(28+tou+12,28+tou+16));
6. 课设答辩的时候薛老师很负责的提出了我们组的设计存在的问题是:一次性显示了所有数据包的信息但是不能去挑选具体的数据包去分析是哪个协议。->于是我们在判断语句中输入要挑选的数据包,然后去判断是否存在这个数据包,然后输出分析数据包的内容。
具体解决问题的代码如下(附录中也有):
在循环中输入想查看的包的序号
System.out.print("输入你想查看的包序号");
    Scanner input=new Scanner(System.in);
    int num=input.nextInt();//输入你要选择看的包序号
    num=num-1;
    for(int i = 0; packet[i] != null && i < max-1; i++) 

{
if(i==num) //如果选的那个数字和循环的符合的话去判断是哪个数据包
{
…//中间的就是确定存在,然后去判断是哪个协议的数据包从而输出
}
}

```

webserver

一、反射:
  反射是框架设计的灵魂(框架是半成品软件,可以在框架的基础上进行软件开发,简化编码)。
将类的各个组成部分封装成其他对象

TCP编程

一、TCP(面向连接的通信)
  TCP通信能实现两台计算机之间的数据交互,通信的两端,要严格区分客户端(Client)和服务器(Server)。
二、通信步骤(通信原理)

  1. 服务器端先启动
  2. 客户端请求–>服务器端
  3. 客户端< – >服务器端【逻辑连接(有一个对象)
  4. 逻辑连接含有客户端提供的** IO对象 **(字节流对象)

** IO对象 **
TCP连接的示意图:

  • 注意:
  1. 服务器必须明确和哪个客户端交互,而且需要多个IO流对象。
  • 服务器端方法 ** accpet **,客户端获取 –> 客户端对象。
  • 服务器(没有IO流) –> 服务器获取请求客户端对象Socket
  • (服务器用的客户端的IO流交互)
  • 服务器使用客户端的字节输入流(读取)客户端发送的数据
  • 服务器使用客户端的字节输出流(回写)给客户端数据

Server(服务器)

1
2
3
4
1.指定端口 使用ServerSocket创建服务器
2.阻塞式等待连接accept
3.操作:使用输入输出流操作
4.释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args)throws IOException {
System.out.println("----Server(服务器)----");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket server=new ServerSocket(8088);
//2.阻塞式等待连接accept
Socket client=server.accept();
System.out.println("一个客户端建立了连接");
//3.操作:使用输入输出流操作
DataInputStream shuru=new DataInputStream(client.getInputStream());/用DataInputStream输入流
String data=shuru.readUTF();//输入
//4.释放资源
shuru.close();//释放shuru
client.close();//释放Client
server.close();//释放server服务器对象
}
}

Client(客户端)

1
2
3
1.建立连接:使用Socket建立窗户段+服务的地址和端口
2.第一步连接好了直接操作:使用输入输出流操作
3.释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException{
System.out.println("----Client(客户端)----");
//1.建立连接:使用Socket建立窗户段+服务的地址和端口
Socket client=new Socket("localhost",8088);//创建client对象去接收服务器的东西
//2.第一步连接好了直接操作:使用输入输出流操作
DataOutputStream shuchu=new DataOutputStream(client.getOutputStream());//用DataOutputStream输出流
String data="hello";//输出一个字符串 hello
shuchu.writeUTF(data);//shuchu写入
shuchu.flush();
//3.释放资源
shuchu.close();//释放输出
client.close(); //释放client对象
}
}

三、TCP文件上传
  在前面的基础上只需要将传输的数据做更改即可达到单向传输!

Client(客户端)

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
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException{
System.out.println("----Client(客户端)----");

BufferedReader console=new BufferedReader(new InputStreamReader(System.in));//用BufferedReader类型去创建输入用户名和密码
System.out.println("请输入用户名");
String uname=console.readLine();
System.out.println("请输入密码");
String upassword=console.readLine();

//1.建立连接:使用Socket建立窗户段+服务的地址和端口
Socket client=new Socket("localhost",8088);
//2.第一步连接好了直接操作:使用输入输出流操作
DataOutputStream shuchu=new DataOutputStream(client.getOutputStream());//输
shuchu.writeUTF("uname="+uname+"&"+"upassword="+upassword);
shuchu.flush();
//3.释放资源
shuchu.close();
client.close();
}
}

Server(服务器)

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
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args)throws IOException {
System.out.println("----Server(服务器)----");
//1.指定端口 使用ServerSocket创建服务器
ServerSocket server=new ServerSocket(8088);
//2.阻塞式等待连接accept
Socket client=server.accept();
System.out.println("一个客户端建立了连接");
//3.操作:使用输入输出流操作
DataInputStream shuru=new DataInputStream(client.getInputStream());//输入流
String datas=shuru.readUTF();

//分析数据
String[] dataArray=datas.split("&");//用&分割
for(String info:dataArray)//增强型for循环输出
{
String[] userinfo=info.split("=");
System.out.println(userinfo[0]+"-->"+userinfo[1]);

}

//4.释放资源
shuru.close();
client.close();
server.close();
}
}

代码结果如下:

  • 客户端的截图:

  • 服务器的截图:

传输协议(UDP)

一、网络爬虫(虚拟)

  1. 获取URL
    URL url=new URL("https://www.jd.com")
  2. 下载资源
  3. 分析
  4. 处理

代码实现(取京东的数据):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
public class pachongle{
public static void main(String[] args) throws Exception {//抛出异常
URL url=new URL("https://www.jd.com");//获取京东URL
InputStream is=url.openStream();//输入流
BufferedReader br=new BufferedReader(new InputStreamReader(is,"UTF-8"));/京东的是UTF-8
String msg=null;//定义一个字符串msg
while(null!=(msg=br.readLine()))
{
System.out.println(msg);//输出
}
br.close();//一定要记得br对象用完之后关闭

}
}

代码结果如下:
京东的所有源文件(浏览器中的源文件)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
public class pachongle{
public static void main(String[] args) throws Exception {
URL url=new URL("https://www.dianping.com");//换成了点评网址
InputStream is=url.openStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is,"UTF-8"));
String msg=null;
while(null!=(msg=br.readLine()))
{
System.out.println(msg);
}
br.close();

}
}
  • 提示403问题(有权限)通过简单的抓取无法做到
1
2
3
4
5
6
Exception in thread "main" java.io.IOException: Server returned HTTP response code: 403 for URL: https://www.dianping.com
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
at java.net.URL.openStream(Unknown Source)
at pachong.pachongle.main(pachongle.java:9)
  • 模拟浏览器HttpURLConnection
  1. //get从服务器获取资源
    对象.setRequestMethod("GET");
  2. //post往服务器上推数据
    对象.setRequestProperty("XXXXX");
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
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class pachongle{
public static void main(String[] args) throws Exception {
URL url=new URL("https://www.dianping.com");
//用HttpURLConnection类
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
//get从服务器获取资源
conn.setRequestMethod("GET");
//post往服务器上推数据
conn.setRequestProperty("XXXXX");

BufferedReader br=new BufferedReader(new InputStreamReader(conn.InputStream(),"UTF-8"));
String msg=null;
while(null!=(msg=br.readLine()))
{
System.out.println(msg);
}
br.close();

}
}

二、UDP(非面向连接)

  1. 使用基于UDP协议的Socket网络编程实现
  2. 不需要利用IO流实现数据传输
  3. 每个数据发送单元被统一封装成数据包。发送方将数据包发送到网络中,数据包在网络中寻找目的地。

UDP基本概念:

  • DatagramSocket:用于发送/接收数据包的套接字
  1. send(DatagramPacket 对象)
  2. receive(DatagramPacket 对象)
  3. close()
  • DatagramPacket:数据包
    主要创建对象new(容器,0,长度)

发送端(client)

1
2
3
4
5
1.使用DatagramSocket端口创建接收端
2.准备数据(转成字节数组)
3.封装成DatagramPacket包裹(指定目的地)
4.发送包裹send(DatagramPacket p)
5.释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class udpClient{
public static void main(String[] args) throws Exception{
System.out.println("发送方启动中...");
//1.使用DatagramSocket端口创建接收端
DatagramSocket client=new DatagramSocket(8888);
//2.准备数据(转成字节数组)
String data="西安工程大学";
byte[] datas=data.getBytes();
//3.封装成DatagramPacket包裹(指定目的地)
DatagramPacket packet=new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999));
//4.发送包裹send(DatagramPacket p)
client.send(packet);
//5.释放资源
client.close();

}
}

接收端(server)

1
2
3
4
5
1.使用DatagramSocket端口创建接收端
2.准备容器,封装成DatagramPacket包裹
3.阻塞式接收包裹receive(DatagramPacket p)
4.分析数据 getData()/getLength()
5.释放资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class udpServer{
public static void main(String[] args) throws Exception {
System.out.println("接收方启动中...");
//1.使用DatagramSocket端口创建接收端
DatagramSocket server=new DatagramSocket(9999);//发送的包里面也必须是9999
//2.准备容器,封装成DatagramPacket包裹
byte[] container=new byte[1024*60];
DatagramPacket packet=new DatagramPacket(container,0,container.length);
//3.阻塞式接收包裹receive(DatagramPacket p)
server.receive(packet);
//4.分析数据 getData()/getLength()
byte[] datas=packet.getData();
int len=packet.getLength();
System.out.println(new String(datas,0,len));
//5.释放资源
server.close();

}
}

代码结果如下:


  • 多次交流的前提:(多次输入)

发送端(client)

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
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class udpClient{
public static void main(String[] args) throws Exception{
System.out.println("发送方启动中...");
//1.使用DatagramSocket端口创建接收端
DatagramSocket client=new DatagramSocket(8888);
//2.准备数据(转成字节数组)
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));//使用这个控制台输入

while(true) //多了一个while循环
{
String data=reader.readLine();//对象不断输入

byte[] datas=data.getBytes();
//3.封装成DatagramPacket包裹(指定目的地)
DatagramPacket packet=new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",9999));
//4.发送包裹send(DatagramPacket p)
client.send(packet);
if(data.equals("bye")) //当输入的数据为bye时输出
{
break;
}
}
//5.释放资源
client.close();
}
}

接收端(server)

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
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class udpServer{
public static void main(String[] args) throws Exception {
System.out.println("接收方启动中...");
//1.使用DatagramSocket端口创建接收端
DatagramSocket server=new DatagramSocket(9999);//发送的包里面也必须是9999
//2.准备容器,封装成DatagramPacket包裹
while(true) { //比之前的多了一个while循环
byte[] container=new byte[1024*60];
DatagramPacket packet=new DatagramPacket(container,0,container.length);
//3.阻塞式接收包裹receive(DatagramPacket p)
server.receive(packet);
//4.分析数据 getData()/getLength()
byte[] datas=packet.getData();
int len=packet.getLength();
String data=new String(datas,0,len);
System.out.println(data);
if(data.equals("bye")) //当最后的数据为bye就结束
break;
}
//5.释放资源
server.close();

}
}

三、UDP多次交流(多线程)

TalkReceive类

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
package UDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class TalkReceive implements Runnable {
private DatagramSocket server;
//1.
public TalkReceive(int port) {
try {
server=new DatagramSocket(port);//抛出异常
} catch (SocketException e) {
e.printStackTrace();
}
}

//2.

@Override
public void run() { //将封装udpServer中的while循环内容
while(true) {
byte[] container=new byte[1024*60];
DatagramPacket packet=new DatagramPacket(container,0,container.length);
//3.阻塞式接收包裹receive(DatagramPacket p)
try {
server.receive(packet);
//4.分析数据 getData()/getLength()
byte[] datas=packet.getData();
int len=packet.getLength();
String data=new String(datas,0,len);
System.out.println(data);
if(data.equals("bye"))
{
break;
}

} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}

//5.释放资源
server.close();
}

}
}

TalkSend类

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
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;

/*
* 封装updTalkClient
*/
public class TalkSend implements Runnable{
//1
private DatagramSocket client;
private BufferedReader reader;
private String toIP;//对方地址
private int toPort;//对方端口
public TalkSend(int port,String toIP,int toPort) {
this.toIP=toIP;
this.toPort=toPort;
try {
client=new DatagramSocket(port);
reader=new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
//2
@Override
public void run() { //直接将updTalkClient中的while拿过来
while(true)
{
String data;
try {
data = reader.readLine();
byte[] datas=data.getBytes();
//3.封装成DatagramPacket包裹(指定目的地)
DatagramPacket packet=new DatagramPacket(datas,0,datas.length,new InetSocketAddress(this.toIP,this.toPort));//将本地主机换成toIP和toPort端口
//4.发送包裹send(DatagramPacket p)
try {
client.send(packet);
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
if(data.equals("bye"))
{
break;
}
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}

//5.释放资源
client.close();
}
}


}

然后构建两个对话类

TalkTeacher类

1
2
3
4
5
6
7

public class TalkTeacher {
public static void main(String[] args) {
new Thread(new TalkReceive(9999)).start();//接收9999
new Thread(new TalkSend(5555,"localhost",8888)).start();//8888发送
}
}

TalkStudent类

1
2
3
4
5
6
7
8
9
/*
* 加入多线程,实现双向交流 模拟在线咨询
*/
public class TalkStudent {
public static void main(String[] args) {
new Thread(new TalkSend(7777,"localhost",9999)).start();//9999发送
new Thread(new TalkReceive(8888)).start();//接收8888
}
}

四、TCP的使用(面向连接可靠)
相对于UDP而言,TCP是一种面向连接的通讯方式,提供一种可靠的方法。

第十届蓝桥杯省赛

一、组队问题

  • 问题描述
    作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容。
    每位球员担任 1 号位至 5 号位时的评分如下表所示。请你计算首发阵容 1
    号位至 5 号位的评分之和最大可能是多少?

  • 问题分析
      这个题目我记得当时我拿到手里没考虑写代码,就是手算的答案490!今天好好考虑了一下这个题目,其实用暴力求解就可以。
      用一个二维数组来存放这个表的信息,然后设置一些变量来代表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
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int[][] team = new int[20][5];
for (int i = 0; i < 20; i++)
{
for (int j = 0; j < 5; j++)
{
team[i][j] = input.nextInt();
}
}

int maxSum = 0;
for (int i = 0; i < 20; i++)
for (int j = 0; j < 20; j++)
for (int k = 0; k < 20; k++)
for (int h = 0; h < 20; h++)
for (int g = 0; g < 20; g++)
if ((i != j && i != k && i != h && i != g) && (j != k && j != h && j != g)&& (k != h && k != g) && h != g)//必须五个人不同才可以
{
int max = team[i][0] + team[j][1] + team[k][2] + team[h][3] + team[g][4];//循环取值计算出每种可能的值
if (max > maxSum)
maxSum = max;//输出最大值的可能取值
}
System.out.println(maxSum);
}
}
  • 代码结果如下:
    输出:490

二、不同子串

  • 问题描述
    一个字符串的非空子串是指字符串中长度至少为 1 的连续的一段字符组成 的串。例如,字符串aaab 有非空子串a, b, aa, ab, aaa, aab, aaab,一共 7 个。 注意在计算时,只算本质不同的串的个数。
    请问,字符串0100110001010001 有多少个不同的非空子串?

  • 问题分析
      我记得当时都没算出来,一遇到这种题目我就死了,学完了JAVA的Set集合之后发现可以直接调用其中的方法快速解题!(substring(int i,int j))

  • 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;
public class Main{
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
String s=input.nextLine();
Set<String> set=new TreeSet<String>();
for (int i = 1; i <= s.length(); ++i)
{// 长度
for (int j = 0; j <= s.length() - i; ++j)
{// 起点
if (!set.contains(s.substring(j, j + i)))
set.add(s.substring(j, j + i));//增加个数
}
}
System.out.println(set.size());//输出add之后的长度
}
}
  • 代码结果如下:


三、数列求值

  • 问题描述
    给定数列 1, 1, 1, 3, 5, 9, 17, …,从第 4 项开始,每项都是前 3 项的和。求
    第 20190324 项的最后 4 位数字。
  • 问题分析
      首先想到的就是用递归求解,但是考虑会超时和内存过大,所以考虑使用动态规划/循环求解;接下来考虑求后四位的话我们不用考虑前面的数字,所以每次求解出来答案就对其与10000取余得出答案。
  • 循环求解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package javaapplication1;
import java.util.Scanner;
public class JavaApplication1 {
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];//用数组去存放这个结果
a[0]=1;
a[1]=1;
a[2]=1;//给前三个数字赋值
for(int i=3;i<n;i++)
{
a[i]=(a[i-1]+a[i-2]+a[i-3])%10000;//算出每一个值就对其取余(前面的位数不考虑)
}
System.out.println(a[n-1]); //输出20190324项的结果
}

}
  • 动态规划:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class qiujie{
public static void main(String[] args) {
int a = 1, b = 1, c = 1;
// 要是求第四项,则i < 4, 同理推得求20190324,则i < 20190324。
for (int i = 3; i < 20190324; i++) {
int temp = (a + b + c) % 10000;
a = b;
b = c; //不断地更替三个数值,就可以减少重复计算中间值
c = temp;
}
System.out.println(c);
}
}
  • 代码结果如下:
    输出:4659

四、数的分解

  • 问题描述
    把 2019 分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?
    注意交换 3 个整数的顺序被视为同一种方法,例如1000+1001+18和1001+1000+18被视为同一种。

  • 问题分析
      一开始就想着三个数字从0-2019循环暴力判断符合条件的输出,但是发现三层循环复杂度太大,最后选择两层循环,(第三个值=2019-第一个值-第二个值)。将判断不包含数字 2 和 4的情况写成一个Ok方法。

  • 代码如下:

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
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int sum=0;
for(int i=1;i<=n/2;i++)//因为防止重复计数,因此i只能到n/2处
{
if(Ok(i))//如果满足条件去找j
{
for(int j=i+1;(j<n)&&(j<(n-i-j));j++)//各不相同所以j从i+1开始,并且满足第二个数小于第三个数(递增的思路)
{
int k=n-i-j; //直接用减法(减少三层循环的时间复杂度)
if(Ok(j)&&Ok(k))
sum++;//满足条件就让结果可能+1
}
}
}

System.out.println(sum);

}

private static boolean Ok(int i) {
while(i!=0)
{
if(i%10==2||i%10==4) //把数拆开如果有2和4有关就要返回错误(false)
return false;
else
i=i/10;
}
return true;
}

}
  • 代码结果如下:


五、特别数的和

  • 问题描述
    小明对数位中含有 2、0、1、9的数字很感兴趣(不包括前导 0),在1到40 中这样的数包括 1、2、9、10至32、39和40,共28个,他们的和是574。请问,在1到n中,所有这样的数的和是多少?
    【输入格式】
    输入一行包含两个整数 n。
    【输出格式】
    输出一行,包含一个整数,表示满足条件的数的和。
    【样例输入】
    40
    【样例输出】
    574
    【评测用例规模与约定】
    对于 20% 的评测用例,1 ≤ n ≤ 10。 对于 50% 的评测用例,1 ≤ n ≤ 100。 对于 80% 的评测用例,1 ≤ n ≤ 1000。 对于所有评测用例,1 ≤ n ≤ 10000

  • 问题分析
      这道题就是考虑将一个数字不断地拆开判断每一位是不是和四个数字有关系,然后编写一个判断函数duibudui()去判断,循环一个一个数字去判断。主要是判断的函数考虑%10取数(1234%10=4取出最后一位),/10拆数(1234/10=123拆小一点)。

  • 代码如下:

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
package xiaosai;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int sum=0;
for(int i=1;i<=n;i++)//循环调用方法满足就sum加上当前值
{
if(duibudui(i))
sum+=i;
}
System.out.println(sum);//输出最终值
}

public static boolean duibudui(int i) //判断是不是满足题意
{
每次循环就是将数字拆小(直到最后拆没了就跳出来)
while(i!=0)
{
if (i%10==2||i%10==0||i%10==1||i%10==9)//每次取出一位判断是不是和2/0/1/9四个数字有关(1234%10=4)
return true;
i/=10;//将这个判断的数字拆小(1234/10=123)
}
return false;
}

}
  • 代码结果如下:


六、年号子串

  • 问题描述
    小明用字母 A 对应数字 1,B 对应 2,以此类推,用 Z 对应 26。对于 27 以上的数字,小明用两位或更长位的字符串来对应,例如 AA 对应 27,AB 对 应 28,AZ 对应 52,LQ 对应 329。
    请问 2019 对应的字符串是什么?

  • 问题分析
      当时是手算的答案,现在下来仔细看了看也就是26进制,只不过就是拆一次数判断出来的结果放在数组之后要反序输出。

  • 代码如下:

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
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
char[] a={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};//直接利用下标取数
char[] b=new char[10];
int m=1;
int i=0;
if(n<=26)
System.out.println(a[n-1]);//26之内就输出对应的结果
else
{
while(n!=0)
{
m=n%26; //拆开这个数最低位判断输出哪个字母
b[i++]=a[m-1];//因为A是0,所以输出a[m-1]
n=n/26; //然后将判断的数组拆成更小的数
}
}

for(int j=b.length-1;j>=0;j--) //反序输出
{
if(b[j]!=0)
System.out.print(b[j]);
}

}
}
  • 代码结果如下:


七、等差数列

  • 问题描述
    数学老师给小明出了一道等差数列求和的题目。但是粗心的小明忘记了一部分的数列,只记得其中N 个整数。
    现在给出这N 个整数,小明想知道包含这N 个整数的最短的等差数列有几项?
    【输入格式】
    输入的第一行包含一个整数N。
    第二行包含N 个整数
    【输出格式】
    输出一个整数表示答案。
    【样例输入】
    5
    2 6 4 10 20
    【样例输出】
    10
    【样例说明】
    包含2、6、4、10、20 的最短的等差数列是2、4、6、8、10、12、14、16、18、20。
    【评测用例规模与约定】
    对于所有评测用例,2≤N≤1000002≤N≤100000

  • 问题分析
      这道题其实主要是有坑(d=0的情况),只需要将输入的数字存放在数组中然后排序之后找到两两之间最小的差就是d(因此输入的数字不一定是相邻的,可能是中间隔了好几个数),利用等差数列的第An项公式:An=A1+(n-1)*d求出n就是所求的值

  • 代码如下:

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
package xiaosai;
import java.util.Arrays;
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner input=new Scanner(System.in);
int n=input.nextInt();
int[] a=new int[n];
for(int i=0;i<a.length;i++)
{
a[i]=input.nextInt();//输入数字
}
Arrays.sort(a);//排序
int d=100;
int cha=0;
for(int i=0;i<a.length-1;i++)
{
cha=a[i+1]-a[i];
if(cha<d)//依次两两判断最小的差距就是公式d
d=cha;
}
if(d==0)
System.out.println(n);
else
{
n=(a[a.length-1]-a[0])/d+1;//利用数组公式求出n(最小的就应该是排序之后的第一个和最后一个之间的数列)
System.out.println(n);
}
}
}
  • 代码结果如下:

网络编程

一、网络编程

  • 端口:实现多个电脑软件交互(app之间);
  • URL:区分软件的资源;
  • Ip:通过ip地址定位电脑(公网->内网);
  • 协议:交流的方式(例如:普通话);
    例如:传输层的TCP/UDP协议
TCP协议 UDP协议
面向连接 非面向连接
不高效 高效
可靠 不可靠

二、InetAddress类
java.net.InetAddress—>表示Internet协议(IP)地址

  • InetAddress类的静态方法
  1. getLocalHost返回本机
  2. getByName根据域名DNS/IP地址—>解析IP地址
  • 成员方法(对象调用)
  1. getHostAddress返回地址
  2. getHostName返回计算机名

举例代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.net.InetAddress;
import java.net.UnknownHostException;
public class JiaNLi {
public static void main(String[] args) throws UnknownHostException {
//创建getLocalHost方法创建一个InetAddress对象
InetAddress addr=InetAddress.getLocalHost();
System.out.println(addr.getHostAddress());//返回:10.2.41.239
System.out.println(addr.getHostName());//DESKTOP-VMNQVVJ

//根据域名可以得到netAddress对象
addr=InetAddress.getByName("www.baidu.com");//使用域名www.baidu.com
System.out.println(addr.getHostAddress());//返回百度服务器的ip:39.156.66.18
System.out.println(addr.getHostName());//www.baidu.com

}
}

代码结果如下:


三、端口(区分软件)

  • 端口分类:
公认端口 注册端口 动态/私有端口
0-1023 1024-49151 49152-65535
分配给专用的 用户进程/应用程序 一般设置这个范围
  • 查看端口情况:

查看所有端口:netstat -ano

查看指定端口:netstat -aon|findstr “xxx”

查看指定进程:tasklist|findstr “xxx”

查看具体程序:使用任务管理器查看PID


四、InetSocketAddress类
java.net.InetSocketAddress—>实现IP套接字地址(IP地址+端口号),可以是一对(主机号+端口号),在这种情况下主机号要DNS一下IP地址。

  • 构造器:
    new InetSocketAddress("地址|域名",端口)
    例如:
    `InetSocketAddress socketAddress=new InetSocketAddress("127.0.0.1",8080);`
    `InetSocketAddress socketAddress2=new InetSocketAddress("localhost",9000);`
  • 方法:
  1. getAddress:返回地址
  2. getPort():返回端口号
  3. getHostString:返回主机号/地址的String形式
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.net.InetAddress;
import java.net.InetSocketAddress;
public class JiaNLi {
public static void main(String[] args) {
//构造器:new InetSocketAddress("地址|域名",端口)
InetSocketAddress socketAddress=new InetSocketAddress("127.0.0.1",8080);
InetSocketAddress socketAddress2=new InetSocketAddress("localhost",9000);
System.out.println(socketAddress.getHostName()); //返回主机名--127.0.0.1
System.out.println(socketAddress2.getAddress());//返回地址--localhost/127.0.0.1
System.out.println(socketAddress2.getPort());//获取端口号--9000
System.out.println(socketAddress2.getHostString());返回主机名/地址的String形式--localhost
}
}

代码结果如下:


五、URL(区分软件资源)
  URI(统一资源标志符)分类:

URL URN
统一资源定位符 统一资源名称
一种定位资源的主要访问机制的字符串 特定命名空间的唯一名称/ID来标识资源

举例:
  在www上,每一信息资源都有统一且唯一的地址(URL)—>http://www.baidu.com:80/index.html?uname=shsxt&age=18#a,由四部分组成:

  1. 协议:getProtocol()
  2. 存放资源的主机域名:getHost()
  3. 端口号(http默认80):getPort()
  4. 请求资源:getFile(显示参数)/getPath(不显示参数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.net.MalformedURLException;
import java.net.URL;
public class JiaNLi {
public static void main(String[] args)throws MalformedURLException {
URL url=new URL("http://www.baidu.com:80/index.html?uname=shsxt&age=18#a");
//获取四个值
System.out.println("协议"+url.getProtocol());//协议http
System.out.println("域名"+url.getHost());//域名www.baidu.com
System.out.println("请求资源"+url.getFile());//请求资源/index.html?uname=shsxt&age=18
System.out.println("请求资源"+url.getPath());//请求资源/index.html
System.out.println("端口"+url.getPort());//端口80
``//参数
System.out.println("参数"+url.getQuery());//参数uname=shsxt&age=18
//锚点
System.out.println("锚点"+url.getRef());//锚点a

}
}

代码结果如下:

等待唤醒机制

一、线程间通信

  • 线程间通信:多个线程在处理同一个资源,但是处理的动作(线程任务)不同。
  • 等待唤醒机制:—>保证线程间通信有效利用
    资源!

二、等待唤醒机制

  • 通信:对包子的状态进行判断
  1. 没有包子–>吃货线程唤醒包子铺线程–>吃货线程等待–>包子铺线程做包子–>做好包子–>修改包子的状态(无–>有)
  2. 有包子–>包子铺线程唤醒吃货线程–>包子铺线程等待–>吃货吃包子–>吃完包子–>修改包子的状态(有–>无)
  • 等待唤醒使用的Object类方法
  1. wait:线程不再活动,不再参与调度,因此不会浪费cpu资源,也不会去竞争锁(进入waiting状态)–>等待notify()方法进入调度队列。
  2. notify:可以唤醒其中一个线程(有一定规律)。
  3. notifyAll:可以唤醒所有线程。
  • 注意点:
  1. 两个方法必须使用同一锁对象调用
  2. 两个方法–>Object类的方法
  3. 两个方法必须在同步代码块(synchronized(){})/同步函数中使用(保证唯一和同步机制)

三、生产者与消费者问题

  • 资源类:包子类:
     包子的属性:皮/馅
     包子的状态:有true/无false

  • 生产者(包子铺)类:是一个线程类,可以继承Thread

  1. 线程任务(run):生产包子
  2. 对包子状态判断
  • true(有包子):
      (1)调用wait方法进入等待状态

  • false(没包子):
      (1)包子铺生产包子
      (2)生产好包子将状态改为true
      (3)唤醒吃货线程
      (4)吃货线程吃包子

  • 消费者(吃货)类:是一个线程类,可以继承Thread

  1. 线程任务(run):吃包子
  2. 对包子状态判断
  • true(有包子):
      (1)调用wait方法进入等待状态

  • false(没包子):
      (1)吃货线程吃包子
      (2)将状态改为false
      (3)唤醒包子铺线程
      (4)生产包子

  • 测试类(含main方法)

  1. 创建包子对象:
  2. 创建包子铺线程:
  3. 创建吃货线程:

四、线程池(容器)

  • 容器—>集合(ArrayList<Thread>/HashSet/LinkedList<Thread>/HashMap)

(基本使用ArrayList集合/LinkedList集合)

  • 分析原理:
    当程序第一次启动—>创建多个线程(放入集合)—>需要使用时从集合中取出线程
     1. 如果是List集合
      Thread t=list.remove(0):返回的是被移除的元素(线程只能被一个任务使用)
      list.add(t):使用完线程,归还给线程池
     2. 如果是Linked集合
      Thread t=linked.removeFirst():一个一个线程被调用
      linked.addLast(t):使用完线程,归还给线程池

五、线程池的使用(JDK1.5之后提供的)
java.util.concurrent.Excutors  线程池的工厂类(用来产生线程池)
其中一个方法:
static ExecutorService newFixedThreadPool(int nThreads):创建一个可重用固定线程数的线程池
  1. 参数(int nThreads):创建线程池中包含的线程数量
  2. 返回值(ExecutorService接口):返回的是ExecutorService接口的实现类对象,我们可以使用此接口来接受(面向接口编程)
例如:
ExecutorService es=Executors.newFixedThreadPool(2);//用ExecutorService接口接着

java.util.concurrent.ExecutorService接口  线程池接口
其中一个方法:
用来从线程池中获取线程,调用start()方法,执行线程任务:
submit(Runnable task):提交一个Runnable—任务用于执行
void shutdown(): 关闭/销毁线程池的方法


六、线程池的使用步骤

  1. 使用线程池的工厂类Executors内的静态方法newFixedThreadPool生产一个指定的线程数量的线程池
  2. 创建一个类实现Runnable接口—>重写run方法—>设置线程任务
  3. 调用ExecutorService中的方法submit—>传递线程任务(实现类)—>开启线程—>执行run方法
  4. 调用ExecutorService中的方法shutdown—>销毁线程池(不推荐!!)

代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
//1.使用线程池的工厂类Executors内的静态方法newFixedThreadPool生产一个指定的线程数量的线程池
ExecutorService es=Executors.newFixedThreadPool(2); //右边返回的就是一个实现类用接口接着(面向接口编程)
//3. 调用ExecutorService中的方法submit--->传递线程任务(实现类)--->开启线程--->执行run方法
es.submit(new RunnableImpl()); //pool-1-thread-1创建了一个新的线程执行
//线程池一直开启,使用完了会归还给线程池,线程可以继续使用
es.submit(new RunnableImpl()); //pool-1-thread-1创建了一个新的线程执行
es.submit(new RunnableImpl()); //pool-1-thread-2创建了一个新的线程执行

es.shutdown();//销毁线程池

}
}

//2. 创建一个类实现Runnable接口--->重写run方法--->设置线程任务
public class RunnableImpl implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"创建了一个新的线程执行"); //获取线程名称的第一种方式
}
}

代码结果如下:

代码分析

  1. 使用线程池的工厂类Executors内的静态方法newFixedThreadPool生产一个指定的线程数量的线程池
    ExecutorService es=Executors.newFixedThreadPool(2); 用接口来接着(面向接口编程)!!

  2. 创建一个类实现Runnable接口—>重写run方法—>设置线程任务
    public class RunnableImpl implements Runnable {}

  3. 调用ExecutorService中的方法submit—>传递线程任务(实现类)—>开启线程—>执行run方法
    es.submit(new RunnableImpl()); 要用实现类传递线程任务(new RunnableImpl())

  4. 调用ExecutorService中的方法shutdown—>销毁线程池(不推荐!!)
    es.shutdown();


,