网络编程
在网络通信协议下,不同计算机上运行的程序,进行的数据传输
-
应用场景:即使通信、网友对战、金融证券等等,不管是什么场景,都是计算机和计算机之间通过网络进行的数据传输
-
java.net
常见的软件架构
C/S(Client/Server,客户端 / 服务器)架构和 B/S(Browser/Server,浏览器 / 服务器)架构是软件开发中两种常见的软件架构模式,下面为你详细介绍:
C/S 架构
概念
C/S 架构将应用程序分为客户端和服务器两部分。客户端是用户直接交互的界面,负责处理用户的输入和显示结果;服务器则负责处理客户端的请求,提供数据存储和业务逻辑处理等服务。客户端和服务器之间通过网络进行通信。
优点
-
性能较高:客户端可以在本地处理部分业务逻辑,减少了与服务器的通信次数,因此在处理大量数据和复杂业务时性能较好。
-
用户体验好:可以根据用户的需求定制客户端界面和功能,提供更加个性化的用户体验。
-
安全性高:客户端和服务器之间的通信可以采用加密技术,数据存储在服务器端,相对比较安全。
缺点
-
维护成本高:客户端需要安装和维护,当软件更新时,需要对每个客户端进行更新,工作量较大。
-
可扩展性差:当用户数量增加或业务需求变化时,需要对客户端和服务器进行相应的升级和扩展,难度较大。
-
跨平台性差:不同操作系统的客户端需要开发不同的版本,增加了开发成本。
适用场景
-
对性能要求较高的应用,如大型游戏、图形处理软件等。
-
对数据安全性要求较高的应用,如银行的网上银行系统、企业的内部办公系统等。
B/S 架构
概念
B/S 架构是一种基于 Web 技术的架构模式,用户通过浏览器访问服务器上的应用程序。服务器负责处理所有的业务逻辑和数据存储,浏览器只负责显示页面和与用户进行交互。
优点
-
易于维护:只需要对服务器进行维护和更新,用户不需要安装任何客户端软件,通过浏览器即可访问应用程序。
-
可扩展性好:服务器可以根据用户数量和业务需求进行灵活的扩展,如增加服务器数量、升级服务器配置等。
-
跨平台性好:只要有浏览器的设备都可以访问应用程序,不受操作系统的限制。
缺点
-
性能相对较低:所有的业务逻辑都在服务器端处理,浏览器只负责显示页面,因此在处理大量数据和复杂业务时性能相对较低。
-
用户体验受浏览器限制:不同浏览器对页面的渲染效果可能会有所不同,用户体验可能会受到一定的影响。
-
安全性相对较低:由于浏览器是开放的,容易受到网络攻击,如 SQL 注入、XSS 攻击等。
适用场景
-
对维护成本要求较低、用户数量较多的应用,如电子商务网站、社交网络平台等。
-
对跨平台性要求较高的应用,如在线办公系统、在线教育平台等。
以下是一个简单的 Java 示例,分别展示 C/S 架构和 B/S 架构的基本实现。
C/S 架构示例
客户端代码:
java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class CSClient {public static void main(String[] args) {try (Socket socket = new Socket("localhost", 8888);PrintWriter out = new PrintWriter(socket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {out.println("Hello, Server!");String response = in.readLine();System.out.println("Server response: " + response);} catch (IOException e) {e.printStackTrace();}} }
服务器端代码:
java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class CSServer {public static void main(String[] args) {try (ServerSocket serverSocket = new ServerSocket(8888)) {System.out.println("Server is listening on port 8888");try (Socket socket = serverSocket.accept();PrintWriter out = new PrintWriter(socket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {String inputLine = in.readLine();System.out.println("Client message: " + inputLine);out.println("Hello, Client!");}} catch (IOException e) {e.printStackTrace();}} }
B/S 架构示例(使用 Spring Boot)
创建一个简单的 Spring Boot 项目,包含一个控制器类:
java
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class BSApplication { public static void main(String[] args) {SpringApplication.run(BSApplication.class, args);} @GetMapping("/hello")public String hello() {return "Hello, World!";} }
运行该 Spring Boot 应用程序后,在浏览器中访问 http://localhost:8080/hello
即可看到返回的信息。
网络编程三要素
网络编程三要素分别是 IP 地址、端口号和传输协议,以下为你详细介绍:
1. IP 地址
概念
IP 地址是互联网协议地址(Internet Protocol Address)的缩写,它是分配给网络上使用网际协议的设备的数字标签,其作用是唯一标识网络中的设备,就像现实生活中的家庭住址一样,通过 IP 地址可以在网络中找到对应的设备。
分类
-
IPv4:由 32 位二进制数组成,通常用点分十进制表示,例如
192.168.1.1
。IPv4 地址数量有限,目前已经基本分配完毕。 -
IPv6:为了解决 IPv4 地址不足的问题而推出的新一代 IP 协议,由 128 位二进制数组成,通常用冒号分隔的十六进制数表示,例如
2001:0db8:85a3:0000:0000:8a2e:0370:7334
。
相关代码示例(Java 获取本地 IP 地址)
java
import java.net.InetAddress; import java.net.UnknownHostException; public class GetLocalIP {public static void main(String[] args) {try {InetAddress localHost = InetAddress.getLocalHost();System.out.println("本地IP地址: " + localHost.getHostAddress());} catch (UnknownHostException e) {e.printStackTrace();}} }
2. 端口号
概念
端口号是一个 16 位的整数,范围从 0 到 65535。它的作用是标识设备上的应用程序或服务,一台设备上可能同时运行多个网络应用程序,通过端口号可以区分不同的应用程序,从而将数据准确地发送到对应的应用程序。
分类
-
系统端口(0 - 1023):这些端口被系统保留,用于一些知名的服务,例如 HTTP 服务使用的端口号是 80,HTTPS 服务使用的端口号是 443。
-
注册端口(1024 - 49151):这些端口通常由用户程序或服务注册使用,例如 MySQL 数据库默认使用的端口号是 3306。
-
动态端口(49152 - 65535):这些端口用于临时分配给客户端程序,当客户端程序与服务器建立连接时,系统会从动态端口中分配一个端口号给客户端使用。
相关代码示例(Java 使用指定端口创建服务器)
java
import java.io.IOException; import java.net.ServerSocket; public class ServerWithPort {public static void main(String[] args) {try {int port = 8888;ServerSocket serverSocket = new ServerSocket(port);System.out.println("服务器已启动,监听端口: " + port);} catch (IOException e) {e.printStackTrace();}} }
3. 传输协议
概念
传输协议是指在网络中传输数据时所遵循的规则和约定,它定义了数据的传输格式、传输方式、错误处理等内容。不同的传输协议适用于不同的应用场景。
常见传输协议
-
TCP(Transmission Control Protocol,传输控制协议):是一种面向连接的、可靠的、基于字节流的传输协议。在进行数据传输之前,需要先建立连接,传输完成后再断开连接。TCP 协议通过确认机制、重传机制等保证数据的可靠传输,适用于对数据准确性要求较高的场景,例如文件传输、电子邮件等。
-
UDP(User Datagram Protocol,用户数据报协议):是一种无连接的、不可靠的传输协议。它不需要建立连接,直接将数据发送出去,不保证数据的可靠传输,可能会出现数据丢失、乱序等情况。UDP 协议的传输效率较高,适用于对实时性要求较高的场景,例如视频会议、在线游戏等。
相关代码示例(Java 使用 TCP 协议实现简单的客户端和服务器通信)
服务器端代码:
java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class TCPServer {public static void main(String[] args) {try (ServerSocket serverSocket = new ServerSocket(8888)) {System.out.println("服务器已启动,等待客户端连接...");try (Socket socket = serverSocket.accept();PrintWriter out = new PrintWriter(socket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {String inputLine = in.readLine();System.out.println("客户端消息: " + inputLine);out.println("Hello, Client!");}} catch (IOException e) {e.printStackTrace();}} }
客户端代码:
java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; public class TCPClient {public static void main(String[] args) {try (Socket socket = new Socket("localhost", 8888);PrintWriter out = new PrintWriter(socket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {out.println("Hello, Server!");String response = in.readLine();System.out.println("服务器响应: " + response);} catch (IOException e) {e.printStackTrace();}} }
4 IP
-
ip的作用,设备在网络中的地址,是唯一的标识
-
IPv4:目前的主流方案,最多只有2^23次方个ip,目前已经用完了
-
IPv6:为了解决IPv4不够用而出现的,最多可以有2^128次方个ip
-
利用局域网IP解决IP 不够用的问题
Inetaddress类
在 Java 中,InetAddress
类属于 java.net
包,它的主要功能是表示互联网协议(IP)地址。下面详细介绍该类的一些关键知识点:
1. 类的特点
InetAddress
类是一个抽象类,这意味着不能直接使用 new
关键字来创建它的实例。不过,它提供了多个静态方法来获取 InetAddress
实例。
2. 获取 InetAddress
实例
-
通过主机名获取:可以使用
getByName(String host)
方法,该方法会返回一个表示指定主机名的InetAddress
对象。
java
import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressExample {public static void main(String[] args) {try {InetAddress address = InetAddress.getByName("www.example.com");System.out.println(address);} catch (UnknownHostException e) {System.out.println("无法解析主机名: " + e.getMessage());}} }
-
获取本地主机地址:使用
getLocalHost()
方法,它会返回一个表示本地主机的InetAddress
对象。
java
import java.net.InetAddress; import java.net.UnknownHostException;public class LocalHostExample {public static void main(String[] args) {try {InetAddress localHost = InetAddress.getLocalHost();System.out.println("本地主机地址: " + localHost);} catch (UnknownHostException e) {System.out.println("无法获取本地主机地址: " + e.getMessage());}} }
-
通过 IP 地址获取:使用
getByAddress(byte[] addr)
方法,该方法会返回一个表示指定 IP 地址的InetAddress
对象。
java
import java.net.InetAddress; import java.net.UnknownHostException; public class ByAddressExample {public static void main(String[] args) {try {byte[] ip = {127, 0, 0, 1};InetAddress address = InetAddress.getByAddress(ip);System.out.println(address);} catch (UnknownHostException e) {System.out.println("无法解析 IP 地址: " + e.getMessage());}} }
3. 常用方法
-
getHostName()
:返回此 IP 地址的主机名。
java
import java.net.InetAddress; import java.net.UnknownHostException;public class GetHostNameExample {public static void main(String[] args) {try {InetAddress address = InetAddress.getByName("www.example.com");String hostName = address.getHostName();System.out.println("主机名: " + hostName);} catch (UnknownHostException e) {System.out.println("无法解析主机名: " + e.getMessage());}} }
-
getHostAddress()
:返回此 IP 地址的字符串表示形式。
java
import java.net.InetAddress; import java.net.UnknownHostException;public class GetHostAddressExample {public static void main(String[] args) {try {InetAddress address = InetAddress.getByName("www.example.com");String hostAddress = address.getHostAddress();System.out.println("IP 地址: " + hostAddress);} catch (UnknownHostException e) {System.out.println("无法解析主机名: " + e.getMessage());}} }
-
isReachable(int timeout)
:测试是否可以达到该地址。该方法会尝试与该地址建立连接,如果在指定的超时时间内成功建立连接,则返回true
,否则返回false
。
java
import java.net.InetAddress; import java.io.IOException; public class IsReachableExample {public static void main(String[] args) {try {InetAddress address = InetAddress.getByName("www.example.com");boolean isReachable = address.isReachable(5000);System.out.println("是否可以到达: " + isReachable);} catch (IOException e) {System.out.println("发生 I/O 错误: " + e.getMessage());}} }
4. 子类
Inet4Address
和 Inet6Address
是 InetAddress
的具体子类,分别代表 IPv4 和 IPv6 地址。你可以使用 instanceof
运算符来判断一个 InetAddress
对象是 IPv4 还是 IPv6 地址。
java
import java.net.InetAddress; import java.net.UnknownHostException;public class SubclassExample {public static void main(String[] args) {try {InetAddress address = InetAddress.getByName("www.example.com");if (address instanceof java.net.Inet4Address) {System.out.println("这是一个 IPv4 地址");} else if (address instanceof java.net.Inet6Address) {System.out.println("这是一个 IPv6 地址");}} catch (UnknownHostException e) {System.out.println("无法解析主机名: " + e.getMessage());}} }
综上所述,InetAddress
类为 Java 程序与网络地址的交互提供了方便的方式,通过它可以轻松地进行主机名解析、IP 地址获取以及网络可达性测试等操作。
端口号
-
是应用程序在设备中唯一的标识
-
端口号:
-
由两个字节表示的整数,取值范围是0~65535
-
其0~1023之间的端口用于一些知名的网络网络服务或者应用
-
我们自己使用1024以上的端口号就可以了
-
-
注意:一个端口号只能被一个应用程序使用
网络编程中的协议知识点整理
一、网络协议概述
网络协议是计算机网络中进行数据交换而建立的规则、标准或约定的集合。它规定了数据传输的格式、传输顺序、错误处理等方面的内容,确保不同设备之间能够准确、可靠地进行通信。
二、常见网络协议层次模型
1. OSI 七层模型
-
物理层:负责传输比特流,规定了传输介质、接口类型、信号编码等物理特性。例如,以太网的网线接口、光纤的传输标准等。
-
数据链路层:将物理层接收到的比特流封装成帧,进行差错检测和流量控制。常见协议有以太网协议(Ethernet),用于局域网中设备之间的通信。
-
网络层:负责将帧从源节点传输到目标节点,进行路由选择和寻址。主要协议有 IP(Internet Protocol)协议,包括 IPv4 和 IPv6。
-
传输层:提供端到端的可靠通信,确保数据的正确传输。常见协议有 TCP(Transmission Control Protocol)和 UDP(User Datagram Protocol)。
-
会话层:负责建立、管理和终止会话,协调不同应用程序之间的通信。例如,RPC(Remote Procedure Call)协议。
-
表示层:处理数据的表示和转换,如加密、解密、压缩、解压缩等。例如,SSL/TLS 协议用于数据加密传输。
-
应用层:为用户提供应用程序接口,直接面向用户的应用程序。常见协议有 HTTP(Hypertext Transfer Protocol)、FTP(File Transfer Protocol)、SMTP(Simple Mail Transfer Protocol)等。
2. TCP/IP 四层模型
-
网络接口层:对应 OSI 模型的物理层和数据链路层,负责将数据帧在物理网络上传输。
-
网际层:与 OSI 模型的网络层功能相似,主要协议是 IP 协议。
-
传输层:和 OSI 模型的传输层相同,提供 TCP 和 UDP 协议。
-
应用层:包含了 OSI 模型的会话层、表示层和应用层的功能,常见协议有 HTTP、FTP、SMTP 等。
三、常见网络协议详解
1. IP 协议
-
功能:为网络中的设备分配唯一的 IP 地址,实现数据包的路由和转发。
-
版本
:
-
IPv4:采用 32 位地址,地址数量有限,格式为点分十进制,如
192.168.1.1
。 -
IPv6:采用 128 位地址,解决了 IPv4 地址不足的问题,格式为冒分十六进制,如
2001:0db8:85a3:0000:0000:8a2e:0370:7334
。
-
2. TCP 协议
-
特点:面向连接、可靠传输、基于字节流。在传输数据之前,需要先建立连接(三次握手),传输完成后需要断开连接(四次挥手)。
-
三次握手
:
-
客户端向服务器发送 SYN 包,请求建立连接。
-
服务器收到 SYN 包后,向客户端发送 SYN + ACK 包,表示同意建立连接。
-
客户端收到 SYN + ACK 包后,向服务器发送 ACK 包,连接建立成功。
-
-
四次挥手(:确保连接断开,且数据处理完毕)
:
-
客户端向服务器发送 FIN 包,表示请求关闭连接。
-
服务器收到 FIN 包后,向客户端发送 ACK 包,表示同意关闭连接。
-
服务器向客户端发送 FIN 包,表示请求关闭连接。
-
客户端收到 FIN 包后,向服务器发送 ACK 包,表示同意关闭连接。
-
3. UDP 协议
-
特点:无连接、不可靠传输、基于数据报。不需要建立连接,直接发送数据,传输效率高,但不能保证数据的可靠到达。适用于对实时性要求较高、对数据准确性要求较低的场景,如视频直播、在线游戏等。
-
三种通信方式
-
单播
-
下面聊天室的代码就是单播
-
-
组播
-
组播地址:224.0.0.0~239.255.255.255
-
其中224.0.0.0~224.0.0255 位预留的组播地址
-
-
-
广播
-
广播地址255.255.255.255
-
-
-
以下是用 Java 语言实现该聊天室功能的代码示例及解析:
发送端代码(Sender.java)
java
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.*; public class Sender {public static void main(String[] args) throws IOException {// 创建DatagramSocket对象用于发送数据报DatagramSocket ds = new DatagramSocket(); // 创建BufferedReader用于从键盘读取输入BufferedReader br = new BufferedReader(new InputStreamReader(System.in));String line;while (true) {line = br.readLine();// 判断是否输入886,如果是则结束发送if ("886".equals(line)) {break;}// 将输入的字符串转换为字节数组byte[] bys = line.getBytes();// 创建DatagramPacket对象,指定发送的数据、长度、目标地址和端口DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("localhost"), 12345);// 发送数据报ds.send(dp);}// 关闭资源ds.close();} }
接收端代码(Receiver.java)
java
import java.io.IOException; import java.net.*; public class Receiver {public static void main(String[] args) throws IOException {// 创建DatagramSocket对象,指定接收数据的端口DatagramSocket ds = new DatagramSocket(12345);while (true) {// 创建字节数组用于存储接收的数据byte[] bys = new byte[1024];// 创建DatagramPacket对象用于接收数据报DatagramPacket dp = new DatagramPacket(bys, bys.length);// 接收数据报ds.receive(dp);// 获取接收到的数据的实际长度int length = dp.getLength();// 将字节数组转换为字符串并输出String data = new String(bys, 0, length);System.out.println("收到消息: " + data);}} }
代码解析
-
发送端(Sender.java)
-
首先创建
DatagramSocket
对象,这是 UDP 通信中用于发送和接收数据报的套接字。 -
通过
BufferedReader
从键盘读取用户输入。 -
使用
while
循环持续读取输入,当输入为886
时跳出循环。 -
对于每次读取到的非
886
输入,将其转换为字节数组,创建DatagramPacket
对象,指定目标地址(这里用localhost
表示本地主机)和端口(12345
),然后通过send
方法发送数据报。 -
最后关闭
DatagramSocket
资源。
-
-
接收端(Receiver.java)
-
创建
DatagramSocket
对象并指定端口(12345
),用于接收发送端发来的数据报。 -
使用一个无限循环(死循环)持续接收数据报。在循环内,先创建字节数组和
DatagramPacket
对象。 -
通过
receive
方法接收数据报,然后获取数据的实际长度,将字节数组转换为字符串并输出接收到的消息。
-
注意事项:
-
这里发送端和接收端的端口要对应一致(都是
12345
),实际应用中可根据需求修改。 -
代码中发送的目标地址为
localhost
,意味着发送和接收都在本地进行,若要在网络中不同主机间通信,需改为对应主机的 IP 地址。
-
4. HTTP 协议
-
功能:用于在 Web 浏览器和 Web 服务器之间传输超文本(如 HTML 页面)。
-
版本
:
-
HTTP/1.0:无状态协议,每次请求都需要建立新的连接,效率较低。
-
HTTP/1.1:支持持久连接、请求头压缩、分块传输等功能,提高了传输效率。
-
HTTP/2:采用二进制分帧、多路复用、头部压缩等技术,进一步提高了性能。
-
-
请求方法:常见的有 GET(获取资源)、POST(提交数据)、PUT(更新资源)、DELETE(删除资源)等。
5. FTP 协议
-
功能:用于在客户端和服务器之间进行文件传输。
-
工作模式
:
-
主动模式:服务器主动连接客户端的数据端口。
-
被动模式:服务器等待客户端连接其数据端口。
-
6. SMTP、POP3 和 IMAP 协议
-
SMTP(Simple Mail Transfer Protocol):用于发送电子邮件。
-
POP3(Post Office Protocol 3):用于接收电子邮件,将邮件从服务器下载到本地客户端后,服务器上的邮件通常会被删除。
-
IMAP(Internet Message Access Protocol):也是用于接收电子邮件,但可以在服务器上保留邮件副本,方便在不同设备上同步邮件。
四、协议的选择和应用场景
-
TCP 协议:适用于对数据准确性要求较高、对实时性要求较低的场景,如文件传输、网页浏览等。
-
UDP 协议:适用于对实时性要求较高、对数据准确性要求较低的场景,如视频直播、在线游戏等。
-
HTTP 协议:主要用于 Web 应用开发,实现客户端和服务器之间的通信。
-
FTP 协议:用于文件的上传和下载。
-
SMTP、POP3 和 IMAP 协议:用于电子邮件的发送和接收。