Java基础-网络编程
Table of Contents generated with DocToc (opens new window)
# 网络编程
# 网络编程概述
Java是 Internet上的语言,它从语言级上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。 Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在Java的本机安装系统里,由JVM进行控制。并且Java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源。
网络编程的目的: 直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。
网络编程中有两个主要的问题:
如何准确地定位网络上一台或多台主机;定位主机上的特定的应用
找到主机后如何可靠高效地进行数据传输
# 网络通信要素概述
# 通信要素1:IP和端口号
IP地址:InetAddress
唯一的标识Internet上的计算机通信实体)
本地回环地址(hostAddress): 127.0.0.1 主机名(hostName): localhost
IP地址分类方式1:IPV4和 IPV6
- IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。以点分十进制表示,如192.168.0.1
- IPV6: 128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示,数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984
IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168.开头的就是私有址址,范围即为192.168.0.0到192.168.255.255,专门为组织机构内部使用
特点:不易记忆
InetAddress获取IP 域名
@Test public void test(){ try { InetAddress inetAddress = InetAddress.getByName("www.sina.com"); System.out.println("inetAddress = " + inetAddress); InetAddress localHost = InetAddress.getLocalHost(); System.out.println("localHost = " + localHost); System.out.println("localHost.getHostName() = " + localHost.getHostName()); System.out.println("localHost.getHostAddress() = " + localHost.getHostAddress()); System.out.println("localHost.getCanonicalHostName() = " + localHost.getCanonicalHostName()); } catch (UnknownHostException e) { e.printStackTrace(); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
端口号
- 端口号标识正在计算机上运行的进程(程序)
- 不同的进程有不同的端口号
- 被规定为一个16位的整数0~65535
- 端口分类:
- 公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23)
- 注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。
- 动态私有端口:49152~65535。
- 端口号与IP地址的组合得出一个网络套接字:Socket
- 端口号标识正在计算机上运行的进程(程序)
# 通信要素2:网络协议
- 网络通信协议: 计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代码结构、传输控制步骤、出错控制鄠刚定标准。
- 问题:网络协议太复杂: 计算机网络通信涉及内容很多,比如指定源地址和目标地址,加密解密,压缩解压缩,差错控制,流量控制,路由控制,如何实现如此复杂的网络协议呢?
- 通信协议分层的思想: 在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展。
# TCP/IP协议簇
- 传输层协议中有两个非常重要的协议:
- 传输控制协议TCP(Transmission Control Protocol)
- 用户数据报协议UDP(User Datagram Protocol)。
- TCP/IP以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。
- lP(Internet Protocol)协议是网络层的主要协议,支持网间互连的数据通信。
- TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层。
- TCP协议
- 使用TCP协议前,需先建立TCP连接,形成传输数据通道
- 传输前,采用"三次握手"方式,点对点通信,是可靠的
- TCP协议进行通信的两个应用进程:客户端、服务端
- 在连接中可进行大数据量的传输
- 传输完毕,需释放已建立的连接,效率低
- UDP协议
- 将数据、源、目的封装成数据报,不需要建立连接
- 每个数据报的大小限制在64K内
- 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的
- 可以广播发送
- 发送数据结束时无需释放资源,开销小,速度快
- 类DatagramSocket和 DatagramPacket实现了基于UDP协议网络程序。
- UDP数据报通过数据报套接字DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什玉时候可以抵达。
- DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
- UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。如同发快递包裹一样。
# TCP网络编程
示例1:
public class TcpTest1 {
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
try {
//1.创建Socket对象,指明服务器端的ip和端口号
socket = new Socket("127.0.0.1", 8888);
//2.获取一个输出流,用于输出数据
os = socket.getOutputStream();
//3.写出数据
os.write("这是客户端".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void server(){
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream bos =null;
try {
//1.创建ServerSocket对象,指明自己的端口号
serverSocket = new ServerSocket(8888);
//2.调用accept方法表示接收来自于客户端的socket
socket = serverSocket.accept();
//3.获取输入流
is = socket.getInputStream();
//4.读取输入流中的数据
bos = new ByteArrayOutputStream();
int len;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1){
bos.write(buffer, 0, len);
}
System.out.println(bos);
System.out.println("收到了来自于:"+socket.getInetAddress().getHostAddress()+"的信息");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
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
示例2:
/**
* @author zdk
* @date 2021/10/5 20:47
* 客户端发送文件给服务端,服务端将文件保存在本地
*/
public class TcpTest2 {
@Test
public void client(){
Socket socket = null;
OutputStream os = null;
FileInputStream fis = null;
try {
//1.创建Socket对象,指明服务器端的ip和端口号
socket = new Socket("127.0.0.1", 8888);
//2.获取一个输出流,用于输出数据
os = socket.getOutputStream();
//3.写出图片数据
fis = new FileInputStream("搭配.png");
int len;
byte[] buffer = new byte[1024];
while ((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void server(){
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
FileOutputStream fos = null;
try {
//1.创建ServerSocket对象,指明自己的端口号
serverSocket = new ServerSocket(8888);
//2.调用accept方法表示接收来自于客户端的socket
socket = serverSocket.accept();
//3.获取输入流
is = socket.getInputStream();
//4.读取输入流中的数据
fos = new FileOutputStream("搭配1.png");
int len;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1){
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (serverSocket != null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
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
示例3:
/**
* @author zdk
* @date 2021/10/5 20:56
* 从客户端发送文件给服务端,服务端保存到本地。并返回发送成功给客户端。
* 并关闭相应的连接
*/
public class TcpTest3 {
@Test
public void client() throws IOException{
//1.创建Socket对象,指明服务器端的ip和端口号
Socket socket = new Socket("127.0.0.1", 8888);
//2.获取一个输出流,用于输出数据
OutputStream os = socket.getOutputStream();
//3.写出图片数据
FileInputStream fis = new FileInputStream("搭配.png");
int len;
byte[] buffer = new byte[1024];
while ((len = fis.read(buffer)) != -1){
os.write(buffer,0,len);
}
//因为read方法是阻塞式的,在没有收到结束信号前,不会终止,所以需要手动关闭数据的输出
//才能让服务端不会一直去读取客户端的输入流
socket.shutdownOutput();
//4.接收服务端的信息 显示到控制台
InputStream is = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer1 = new byte[20];
while ((len = is.read(buffer1)) != -1){
bos.write(buffer1,0,len);
}
System.out.println(bos);
os.close();
socket.close();
fis.close();
bos.close();
}
@Test
public void server() throws IOException{
//1.创建ServerSocket对象,指明自己的端口号
ServerSocket serverSocket = new ServerSocket(8888);
//2.调用accept方法表示接收来自于客户端的socket
Socket socket = serverSocket.accept();
//3.获取输入流
InputStream is = socket.getInputStream();
//4.读取输入流中的数据
FileOutputStream fos = new FileOutputStream("搭配2.png");
int len;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1){
fos.write(buffer, 0, len);
}
//5.服务器端给出反馈
OutputStream os = socket.getOutputStream();
os.write("文件传输完毕".getBytes());
serverSocket.close();
fos.close();
is.close();
socket.close();
os.close();
}
}
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
# UDP网络编程
示例:
/**
* @author zdk
* @date 2021/10/5 21:20
*/
public class UdpTest {
@Test
public void sender() throws IOException {
DatagramSocket socket = new DatagramSocket();
String str = "这是发送来的数据";
byte[] data = str.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(data,0,data.length, InetAddress.getLocalHost(),8888);
socket.send(datagramPacket);
socket.close();
}
@Test
public void receiver() throws IOException {
DatagramSocket socket = new DatagramSocket(8888);
byte[] buffer = new byte[100];
DatagramPacket datagramPacket = new DatagramPacket(buffer,0,buffer.length);
socket.receive(datagramPacket);
System.out.println(new String(datagramPacket.getData(),0,datagramPacket.getLength()));
}
}
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
# URL编程
# URL类
URL(Uniform Resource Locator):统一资源定位符,它表示Internet上某一资源的地址
它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源
通过URL我们可以访问Internet上的各种网络资源,比如最常见的www,ftp站点。浏览器通过解析给定的URL可以在网络上查找相应的文件或其他资源
URL的基本结构由5部分组成:
- <传输协议>:/<主机名>:<端口号><文件名>#片段名?参数列表
- #片段名:即锚点,例如看小说,直接定位到章节
- 参数列表格式:参数名=参数值&参数名=参数值.....
代码示例
public class UrlTest { @Test public void test1() throws MalformedURLException { URL url = new URL("https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.588ku.com%2Felement_origin_min_pic%2F18%2F08%2F24%2F05dbcc82c8d3bd356e57436be0922357.jpg&refer=http%3A%2F%2Fbpic.588ku.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1636189653&t=9d18acffda7e4021a95e06c0185f53ed"); System.out.println("url.getProtocol() = " + url.getProtocol()); System.out.println("url.getHost() = " + url.getHost()); System.out.println("url.getPort() = " + url.getPort()); System.out.println("url.getPath() = " + url.getPath()); System.out.println("url.getFile() = " + url.getFile()); System.out.println("url.getQuery() = " + url.getQuery()); } @Test public void test2() throws IOException { URL url = new URL("https://image.baidu.com/search/detail?z=0&word=%E4%BA%BA%E7%89%A9&hs=0&pn=0&spn=0&di=&pi=208990&tn=baiduimagedetail&is=&ie=utf-8&oe=utf-8&cs=1243422304%2C530743266&os=&simid=&adpicid=0&lpn=0&fr=albumsdetail&fm=&ic=0&sme=&cg=&bdtype=&oriquery=&objurl=https%3A%2F%2Ft7.baidu.com%2Fit%2Fu%3D1243422304%2C530743266%26fm%3D193%26f%3DGIF&fromurl=ipprf_z2C%24qAzdH3FAzdH3Fooo_z%26e3Bkt2rtvf_z%26e3BvgAzdH3Fip4sAzdH3FdadAzdH3FWSPNgAS0x5l_z%26e3Bip4s&gsm=0&islist=&querylist=&album_tab=%E9%A3%8E%E6%99%AF%E6%97%85%E8%A1%8C&album_id=595"); URLConnection urlConnection = url.openConnection(); urlConnection.connect(); InputStream is = urlConnection.getInputStream(); FileOutputStream fos = new FileOutputStream("test.jpg"); int len; byte[] buffer = new byte[1024]; while ((len = is.read(buffer)) != -1){ fos.write(buffer, 0, len); } is.close(); fos.close(); } }
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