Java网络编程

1

Java网络编程

  网络是我们从小就耳熟能详的名词,大家都喜欢上网冲浪,而且随着科技的进步,时代的发展,我们的网络也变得越来越发达。记得小时候,上网就是指电脑,家里还有那种大屁股显示器(阴极射线管),能玩的游戏非常少,只有CS、红警、传奇、千年等游戏。而现在,游戏种类越来越多,占用资源越来越大,网络也从电脑分布到生活中的各个角落。那么网络是如何传输和连接的呢?下面就和小伙伴们聊一聊网络的知识。

网络定义

网络这里指因特网(Internet),是由很多小的子网互联组合在一起的一个逻辑网络。其中组合方式是通过节点和链路构成,每个子网中连接着若干计算机,基于共同的协议,将资源进行共享。可以将互联网比作这个世界,而每个子网可以看成各个不同的国家,每个节点可以当作一个城市,而链路就是城市之间的通路。

小伙伴们可能会有疑问,两个城市之间的通路有很多,那么如何选择呢?

上面这个问题是路由来完成的。你在某个地点,可以借助多种方式可以到达世界上的任意一个地方,假如你想从合肥到达上海,可以通过很多方式,可以坐车先到达杭州,然后从杭州到达上海。也可以坐车先到达南京,然后从南京到达上海。路由表会动态记录当前的网络拓扑结构,会根据当前的路径选择下一跳到达的目的地。这里也不做过多扩展,感兴趣的小伙伴可以深入了解这些知识。

网络结构

网络的结构分为七层,也称之为OSI(Open System Interconnection)参考模型,是国际化标准组织指定的一套网络体系。分别为应用层、表示层、会话层、传输层、网络层、链路层和物理层。
2

我们从下到上分别介绍每一层的作用

  • 物理层:用作网络数据传输的介质,简单点说就可以理解为生活中的网线,当然还包括集线器、中继器、调制解调器等。
  • 链路层:用作建立数据链路连接,我们有了网线之后,我们还需要建立数据通路,通过这个通路发送给客户端。比如网桥、交换机等设备。
  • 网络层:用作数据传输和分发,在建立好数据通路以后,就可以给我们的设备发送网络信息了,这个时候就需要找到一个合适的路径,所以路由器就是在这一层发挥作用。
  • 传输层:用作数据的逻辑通信,找到了信息下一跳要发送的地址,我们需要借助协议进行传输。如TCP、UDP协议等。
  • 会话层:用作建立端到端连接和提供访问验证,信息通过协议发送到我们的端口上以后,服务器就会对用户进行身份校验。
  • 表示层:用作数据的处理,主要是编解码、加解密等,如URL加密、密码加密、图片编解码等。在身份校验完成后,会对网络中的图片、视频进行编解码。
  • 应用层:用作为网络用户提供接口和服务,在数据编解码后,就可以真正被我们使用了。比如我们用的浏览器,就会直接调用应用层提供的网络访问接口来获取信息了。

UDP编程

UDP(User Datagram Protocol, 用户数据包协议):是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。因为UDP是面向无连接的协议,因此网络传输时要非常小心,传送重要数据可能会产生丢失的现象。也恰恰因为其面向无连接,不需要对方确认收到,只要发送过去即可,因此具有资源消耗小,处理速度快的特点。常常用于处理大型的文件,如音视频等。

Java中已经集成了UDP网络编程所需要的库和接口,我们只需要调用应用层接口即可直接使用。

下面举一个小例子,在代码的注释中,告诉小伙伴应该如何使用。现在要实现一个功能,客户端想服务端发送字符串,服务端接收到后,将字符串进行反转返回给客户端。直到客户端发送”bye server”,服务端发送”bye 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
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
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPDemoClient {
public static void main(String[] args) throws IOException {
// 创建BufferedReader用于读取键盘输入
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));

// 创建写Socket,用于给服务端发送数据包
DatagramSocket socketWrite = new DatagramSocket();

// 创建读Socket,用于读取服务端发送到6666端口上的数据包
DatagramSocket socketRead = new DatagramSocket(6666);

// 创建用于数据读取的字节数组
byte[] data = new byte[1024];
String str;
do {
// 读取键盘输入的字符串到str
str = bufferedReader.readLine();

// 根据字符串创建写数据包,在数据包中指定发送到哪个IP和端口
DatagramPacket packetWrite = new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("192.168.233.1"), 8888);

// 写Socket发送数据
socketWrite.send(packetWrite);

// 创建读数据包,将读入的数据放入字节数组中
DatagramPacket packetReader = new DatagramPacket(data, data.length);

// 读Socket读取数据
socketRead.receive(packetReader);

// 将数据转换为字符串,显示在控制台
System.out.println(new String(packetReader.getData(), 0, packetReader.getLength()));

} while (!str.equals("bye server"));

// 关闭创建的Socket
socketRead.close();
socketWrite.close();
}
}

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPDemoServer {
public static void main(String[] args) throws IOException {
// 创建写Socket,用于给服务端发送数据包
DatagramSocket socketWrite = new DatagramSocket();

// 创建读Socket,用于读取服务端发送到8888端口上的数据包
DatagramSocket socketRead = new DatagramSocket(8888);

// 创建用于数据读取的字节数组
byte[] data = new byte[1024];

// 设置标志位,当读取到的字符串为"bye server"停止
boolean stop;
String str;
do {
// 创建读数据包,将读入的数据放入字节数组中
DatagramPacket packetReader = new DatagramPacket(data, data.length);

// 读Socket读取数据
socketRead.receive(packetReader);

// 将数据转换为字符串
str = new String(packetReader.getData(), 0, packetReader.getLength());

stop = str.equals("bye server");

// 字符串反转
String strReverse = stop ? "bye client" : new StringBuilder(str).reverse().toString();

// 根据反转后的字符串创建写数据包,在数据包中指定发送到哪个IP和端口
DatagramPacket packetWrite = new DatagramPacket(strReverse.getBytes(), strReverse.getBytes().length, InetAddress.getByName("192.168.233.1"), 6666);

// 写Socket发送数据
socketWrite.send(packetWrite);
} while (!stop);

// 关闭创建的Socket
socketRead.close();
socketWrite.close();
}
}

3

TCP编程

TCP(Transmission Control Protocol, 传输控制协议):是一种面向连接的、可靠的传输层协议,面向连接指的是客户端和服务器在彼此交换数据包之前,必须先建立一个TCP连接。因为TCP是面向连接的协议,因此网络传输时具有高可靠性,确保传输数据的正确性。也恰恰因为其面向连接,需要对方确认收到,因此具有资源消耗大,处理速度慢的特点。常常用于处理小型重要文件,如信令交互等。

Java中已经集成了TCP网络编程所需要的库和接口,我们只需要调用应用层接口即可直接使用。

我们用和UDP相同的例子来解释接口的调用方法

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
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class TCPDemoClient {
public static void main(String[] args) throws IOException {
// 创建BufferedReader用于读取键盘输入
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));

// 创建Socket用于连接服务端
Socket socket = new Socket("192.168.233.1", 6666);

// 获取Socket的输出流和输入流
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();


// 创建用于数据读取的字节数组
byte[] data = new byte[1024];
String str;
do {
// 读取键盘输入的字符串到str
str = bufferedReader.readLine();

// 输出流写入数据
outputStream.write(str.getBytes());

// 输入流读取数据
int length = inputStream.read(data);

// 将数据转换为字符串,显示在控制台
System.out.println(new String(data, 0, length));
} while (!str.equals("bye server"));

// 关闭创建的输入输出流和Socket
inputStream.close();
outputStream.close();
socket.close();
}
}

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPDemoServer {
public static void main(String[] args) throws IOException {
// 创建ServerSocket用于连接客户端
ServerSocket serverSocket = new ServerSocket(6666);

// ServerSocket等待客户端的连接,连接成功后创建一个Socket
Socket socket = serverSocket.accept();

// 获取Socket的输出流和输入流
OutputStream outputStream = socket.getOutputStream();
InputStream inputStream = socket.getInputStream();

// 创建用于数据读取的字节数组
byte[] data = new byte[1024];

// 设置标志位,当读取到的字符串为"bye server"停止
boolean stop;
String str;
do {
// 输入流读取数据
int length = inputStream.read(data);

// 将数据转换为字符串
str = new String(data, 0, length);

stop = str.equals("bye server");

// 字符串反转
String strReverse = stop ? "bye client" : new StringBuilder(str).reverse().toString();

// 输出流写入数据
outputStream.write(strReverse.getBytes());
} while (!stop);

// 关闭创建的输入输出流和Socket
inputStream.close();
outputStream.close();
socket.close();
}
}

4

UDP和TCP的区别

我用最简单的方式进行编程,目的是小伙伴们一定要看明白上面的代码。可以看出UDP和TCP的区别包括以下几点

  1. TCP连接方式服务端需要使用一个ServerSocket等待客户端的Socket连接,并返回一个Socket。然后用此Socket与客户端进行通信。
  2. UDP中Socket只能负责收或者发,TCP中Socket既可以收也可以发。
  3. TCP中Socket的建立具有先后关系,如果先运行客户端,则会包错,而UDP不会报错。
  4. UDP中Socket的receive是线程阻塞的。TCP中ServerSocket的accept方法和InputStream的read方法也是线程阻塞的。

网络编程小结

  网络编程是一个软件开发工程师必须掌握的技能,因为平时在学校里,这部分练习非常少,很多小伙伴可能会忽略这个技术。然而在实际的工作中,网络编程是非常常见的,现在的应用软件很少是可以运行在无网络状态下,因此可能会频繁的访问网络,如果没接触过这方面的小伙伴会感觉到困惑。这里主要对小伙伴进行一个科普,在实际的开发中,难点也不在于网络编程。能看懂代码,写出简单的应用即可。

-------------本文结束感谢您的阅读-------------
0%