Java网络编程

一.网络编程概述

  • Java是 Internet 上的语言, 它从语言级上提供了对网络应用程序的支持, 程序员能够很容易开发常见的网络应用程序.
  • Java提供的网络类库, 可以实现无痛的网络连接, 联网的底层细节被隐藏在 Java 的本机安装系统里, 由 JVM 进行控制, 并且 Java 实现了一个跨平台的网络库, 程序员面对的是一个统一的网络编程环境.

计算机网络:
把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统, 从而使众多的计算机可以方便地互相传递信息、共享硬件、软件、数据信息等资源.
网络编程的目的:
直接或间接地通过网络协议与其它计算机进行通讯.
网络编程中有两个主要的问题:
①如何准确地定位网络上一台或多台主机
②找到主机后如何可靠高效地进行数据传输.
如何实现网络中的主机互相通信:
①通信双方地址
②一定的规则(有两套参考模型):
OSI参考模型: 模型过于理想化, 未能在因特网上进行广泛推广
TCP/IP参考模型(或TCP/IP协议): 事实上的国际标准.

Protocol

二.通讯要素

1.IP和端口号

IP 地址: InetAddress
①唯一的标识 Internet 上的计算机
②本地回环地址(hostAddress): 127.0.0.1 主机名(hostName):localhost
③不易记忆
端口号标识正在计算机上运行的进程(程序)
①不同的进程有不同的端口号
②被规定为一个 16 位的整数 0~65535. 其中, 0~1023被预先定义的服务通信占用(如My Sql占用端口3306, http占用端口80等). 除非我们需要访问这些特定服务, 否则, 就应该使用 1024~65535 这些端口中的某一个进行通信, 以免发生端口冲突.

端口号与IP地址的组合得出一个网络套接字(socket).

2.网络通信协议

​ 计算机网络中实现通信必须有一些约定, 即通信协议, 对速率、传输代码、代码结构、传输控制步骤、出错控制等制定标准.
​ 通信协议分层的思想

TCP/IP协议簇

传输层协议中有两个非常重要的协议:
传输控制协议TCP(Transmission Control Protocol)
用户数据报协议UDP(User Datagram Protocol)
TCP/IP 以其两个主要协议: 传输控制协议(TCP)和网络互联协议(IP)而得名, 实际上是一组协议, 包括多个具有不同功能且互为关联的协议.
IP(Internet Protocol)协议是网络层的主要协议, 支持网间互连的数据通信.
TCP/IP协议模型从更实用的角度出发, 形成了高效的四层体系结构, 即物理链路层、IP层、传输层和应用层.

  1. TCP协议:
  • 使用TCP协议前, 须先建立TCP连接, 形成传输数据通道
  • 传输前, 采用“三次握手”方式, 是可靠的
  • TCP协议进行通信的两个应用进程: 客户端、服务端
  • 在连接中可进行大数据量的传输
  • 传输完毕, 需释放已建立的连接, 效率低
  1. UDP协议(视频传输一般用的此协议):
  • 将数据、源、目的封装成数据包, 不需要建立连接
  • 每个数据报的大小限制在64 K内
  • 因无需连接, 故是不可靠的
  • 发送数据结束时无需释放资源, 速度快

3.Socket

  • 利用套接字(Socket)开发网络应用程序早已被广泛的采用, 以至于成为事实上的标准.
  • 通信的两端都要有Socket, 是两台机器间通信的端点
  • 网络通信其实就是Socket间的通信
  • Socket允许程序把网络连接当成一个流, 数据在两个Socket间通过IO传输
  • 一般主动发起通信的应用程序属客户端, 等待通信请求的为服务端

4.InetAddress类

Internet上的主机有两种方式表示地址:
域名(hostName): localhost
IP 地址(hostAddress): 127.0.0.1
InetAddress类主要表示IP地址, 两个子类: Inet4Address、Inet6Address.
InetAddress 类对象含有一个 Internet 主机地址的域名和IP地址: localhost 和 127.0.0.1
域名容易记忆, 当在连接网络时输入一个主机的域名后, 域名解析服务器(DNS)负责将域名转化成IP地址, 这样才能和主机建立连接. -------域名解析

Windows系统中, 访问域名, 先找本机hosts(C:\Windows\System32\drivers\etc\hosts), 是否有输入的域名地址, 没有的话, 再通过DNS服务器, 找主机.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void main(String[] args) throws Exception {
//创建一个InetAddress对象: getByName()
InetAddress inet = InetAddress.getByName("localhost");
//inet = InetAddress.getByName("127.0.0.1");
System.out.println(inet);
//两个方法
System.out.println(inet.getHostName());
System.out.println(inet.getHostAddress());
//获取本机的IP: getLocalHost()
InetAddress inet1 = InetAddress.getLocalHost();
System.out.println(inet1);
System.out.println(inet1.getHostName());
System.out.println(inet1.getHostAddress());
}

三.基于Socket的TCP编程

Java语言的基于套接字编程分为服务端编程和客户端编程, 有两个类Socket类和ServerSocket类

1.TCP编程示例一

客户端给服务端发送信息, 服务端将信息输出在控制台上.
注意: 测试时, 先开启服务端, 再开启客户端

One More Thing 👇
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
// 客户端
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
try {
//1.创建一个Socket的对象, 通过构造器指明服务端的IP地址, 以及其接收程序的端口号
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
//2.getOutputStream(): 发送数据, 方法返回OutputStream的对象
os = socket.getOutputStream();
//3.具体的输出过程
os.write("我是客户端发送的信息".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭相应的流和Socket对象
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 ss = null;
Socket s = null;
InputStream is = null;
try {
//1.创建一个ServerSocket的对象, 通过构造器指明自身的端口号
ss = new ServerSocket(9999);
//2.调用其accept()方法, 返回一个Socket的对象
s = ss.accept();
//3.调用Socket对象的getInputStream()获取一个从客户端发送过来的输入流
is = s.getInputStream();
//4.对获取的输入流进行的操作
byte[] b = new byte[16];
int len = -1;
while ((len = is.read(b)) != -1) {
String str = new String(b, 0, len);
System.out.print(str);
}
System.out.println("收到来自于" + s.getInetAddress().getHostAddress() + "的信息");
} catch (IOException e) {
e.printStackTrace();
} finally {
//5.关闭相应的流以及Socket、ServerSocket的对象
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (s != null) {
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

2.TCP编程示例二

客户端给服务端发送信息, 服务端将信息打印到控制台上, 同时回馈"成功接受"给客户端

One More Thing 👇
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
//客户端
@Test
public void client(){
Socket socket = null;
OutputStream os = null;
InputStream is = null;
try {
socket = new Socket(InetAddress.getByName("127.0.0.1"),9999);
os = socket.getOutputStream();
os.write("我是客户端的信息".getBytes());
//shutdownOutput():执行此方法, 显式的告诉服务端发送完毕!
socket.shutdownOutput();
is = socket.getInputStream();
byte[] b = new byte[16];
int len = -1;
while((len = is.read(b)) != -1){
String str = new String(b,0,len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
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 ss = null;
Socket s = null;
InputStream is = null;
OutputStream os = null;
try {
ss = new ServerSocket(9999);
s = ss.accept();
is = s.getInputStream();
byte[] b = new byte[16];
int len = -1;
//下面的read()方法是阻塞式的, 需要客户端显示的告诉服务端, 发送数据完毕
while((len = is.read(b)) != -1){
String str = new String(b,0,len);
System.out.print(str);
}
os = s.getOutputStream();
os.write("服务端成功接收".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally{
if(os != null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(s != null){
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ss != null){
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

3.TCP编程示例三

从客户端发送文件给服务端, 服务端保存到本地. 并返回“成功接收”给客户端. 并关闭相应的连接.

One More Thing 👇
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
//客户端
@Test
public void client() {
Socket socket = null;
OutputStream os = null;
InputStream is = null;
FileInputStream fis = null;
try {
socket = new Socket(InetAddress.getByName("localhost"),9999);
os = socket.getOutputStream();
fis = new FileInputStream(new File("1.png"));
int length = -1;
byte[] a = new byte[1024];
while((length = fis.read(a))!=-1) {
os.write(a, 0, length);
}
socket.shutdownOutput();
is = socket.getInputStream();
int len = -1;
byte[] b = new byte[16];
while((len = is.read(b))!= -1) {
String str = new String(b, 0, len);
System.out.print(str);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
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 ss = null;
Socket s = null;
InputStream is = null;
OutputStream os = null;
FileOutputStream fos = null;
try {
ss = new ServerSocket(9999);
s = ss.accept();
is = s.getInputStream();
fos = new FileOutputStream(new File("2.png"));
byte b[] = new byte[1024];
int len = -1;
while((len = is.read(b))!=-1) {
fos.write(b, 0, len);
}
System.out.println("收到来自于" + s.getInetAddress().getHostAddress() + "的文件");
os = s.getOutputStream();
os.write("成功接收".getBytes());
} catch (IOException e) {
e.printStackTrace();
}finally {
if(os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(s != null) {
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ss != null) {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

四.基于Socket的TCP编程

  • 类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序.
  • UDP数据报通过数据报套接字 DatagramSocket 发送和接收, 系统不保证UDP数据报一定能够安全送到目的地, 也不能确定什么时候可以抵达.
  • DatagramPacket 对象封装了UDP数据报, 在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号.
  • UDP协议中每个数据报都给出了完整的地址信息, 因此无须建立发送方和接收方的连接.

1.流 程:

  1. DatagramSocket与DatagramPacket
  2. 建立发送端,接收端
  3. 建立数据包
  4. 调用Socket的发送、接收方法
  5. 关闭Socket

发送端与接收端是两个独立的运行程序

One More Thing 👇
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
//发送端
@Test
public void send() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket();
byte[] b = "这是发送端发送过来的数据".getBytes();
DatagramPacket dp = new DatagramPacket(b, 0, b.length, InetAddress.getByName("127.0.0.1"), 9999);
ds.send(dp);
} catch (IOException e) {
e.printStackTrace();
}finally {
if(ds != null) {
ds.close();
}
}
}
//接收端
@Test
public void rceive() {
DatagramSocket ds = null;
try {
ds = new DatagramSocket(9999);
byte[] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b, 0, b.length);
ds.receive(dp);
String str = new String(dp.getData(),0,dp.getLength());
System.out.println(str);
} catch (IOException e) {
e.printStackTrace();
}finally {
ds.close();
}
}

五.URL编程

  • URL(Uniform Resource Locator): 统一资源定位符, 它表示 Internet 上某一资源的地址. 通过 URL 我们可以访问 Internet 上的各种网络资源, 比如最常见的 www, ftp 站点. 浏览器通过解析给定的 URL 可以在网络上查找相应的文件或其他资源.
  • URL的基本结构由5部分组成:
    <传输协议>://<主机名>:<端口号>/<文件名>
    例如: http://127.0.0.1:8080/helloworld/index.jsp
One More Thing 👇
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
@Test
public void download() {
InputStream is = null;
InputStream is2 = null;
FileOutputStream fos = null;
try {
URL url = new URL("https://papertome.com/hello.txt");
//读取服务器上的资源法一:
is = url.openStream();
byte[] b = new byte[16];
int len = -1;
while((len = is.read(b))!=-1) {
String str = new String(b,0,len,"utf-8");
System.out.print(str);
}
//读取服务器上的资源法二:
URLConnection urlConn = url.openConnection();
is2 = urlConn.getInputStream();
fos = new FileOutputStream(new File("hello.txt"));
while((len = is2.read(b))!=-1) {
fos.write(b, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is2 != null) {
try {
is2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

评论