目录
[1.1 IP地址](#1.1 IP地址)
[1.2 端口号](#1.2 端口号)
[1.3 协议](#1.3 协议)
[2.1 定义与特点](#2.1 定义与特点)
[2.2 程序](#2.2 程序)
[3.1 定义与特点](#3.1 定义与特点)
[3.2 程序](#3.2 程序)
[4.1 三次握手](#4.1 三次握手)
[4.2 四次挥手](#4.2 四次挥手)
[4.3 总结](#4.3 总结)
引言
网络编程是指网络设备的行为和流量控制由独立于网络硬件运行的软件处理。用户可以在控制器上编程,实现对网络的配置、控制和管理。网络编程将网络的控制平面和数据平面分离,数据平面不再需要实现各种网络协议的控制逻辑,只需要接收控制平面的操作指令并执行。
一、网络编程三要素
网络编程的三要素包括IP地址、端口号和通信协议。
1.1 IP地址
IP地址是网络中设备的唯一标识。可分为IPv4和IPv6两类。IPv4使用4个字节(32位)来表示一个IP地址,采用点分十进制表示法,例如"192.168.1.1"。IPv6则使用16个字节(128位)来表示一个IP地址,采用冒分十六进制表示法,以应对IPv4地址资源枯竭的问题。
特殊IP地址"127.0.0.1"代表本机地址,通常用于测试。
1.2 端口号
端口号是设备上应用程序的唯一标识。它是一个用两个字节表示的整数,取值范围是0~65535。其中,0~1023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号。
1.3 协议
计算机网络中连接和通信的规则被称为网络通信协议。它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。常见的协议有UDP协议和TCP协议。
OSI参考模型 | TCP/IP参考模型 | TCP/IP参考模型各层对应协议 | 应用 |
---|---|---|---|
应用层 | 应用层 | HTTP、FTP、Telent、DNS... | 应用程序需关注的。如浏览器,邮箱。程序员一般在这层开发 |
表示层 | 应用层 | HTTP、FTP、Telent、DNS... | 应用程序需关注的。如浏览器,邮箱。程序员一般在这层开发 |
会话层 | 应用层 | HTTP、FTP、Telent、DNS... | 应用程序需关注的。如浏览器,邮箱。程序员一般在这层开发 |
传输层 | 传输层 | TCP、UDP... | 选择传输使用的TCP、UDP协议 |
网络层 | 网络层 | IP、ICMP、ARP... | 封装自己的IP,对方的IP等信息 |
数据链路层 | 物理+数据链路层 | 硬件设备。 010101000... | 转换成二进制利用物理设备传输 |
物理层 | 物理+数据链路层 | 硬件设备。 010101000... | 转换成二进制利用物理设备传输 |
二、UDP通信协议与程序
2.1 定义与特点
UDP协议:用户数据报协议(User Datagram Protocol),是传输层的一个主要协议。
- 无连接:在通信之前不需要建立连接,每个数据包独立传输,没有握手过程,这使得UDP的传输延迟较低,适合需要快速传输数据的应用场景。
- 不可靠传输:不保证数据的可靠传输,数据包可能会丢失、重复或乱序到达。协议本身不提供错误检测和重传机制,如果需要可靠性,必须在应用层实现。
- 面向报文:发送方将数据分成独立的报文,每个报文包含完整的消息。接收方按报文接收数据,报文的边界在接收时保持不变。
- 低开销:没有连接建立、维护和终止的开销,也没有复杂的错误控制和流量控制机制,其报头信息较少,仅包含源端口、目标端口、长度和校验和。
- 支持广播和多播:可以将数据包发送到一个或多个网络中的所有主机。
- 实时性好:没有连接建立和维护的开销,加上较低的协议处理时间,UDP适合实时性要求高的应用,如视频会议、语音通信和在线游戏。
2.2 程序
Java中的UDP通信:涉及两个主要类,DatagramSocket和DatagramPacket。
DatagramSocket类用于创建和管理UDP套接字,负责发送和接收数据包,并提供了基本的网络通信功能。DatagramPacket类用于表示一个数据包,它包含发送或接收的数据,以及目标或来源的IP地址和端口。
发送端:
java
import java.io.IOException;
import java.net.*;
public class UdpSend {
public static void main(String[] args) throws IOException {
//1.创建发送数据对象
DatagramSocket ds = new DatagramSocket();
//2.打包数据
String str = "Hello World!";
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10086;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);
//3.发送数据
ds.send(dp);
//4.释放资源
ds.close();
}
}
接收端:
java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpReceive {
public static void main(String[] args) throws IOException {
//1.创建接收数据对象
DatagramSocket ds = new DatagramSocket(10086);
//2.接收数据
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
//阻塞等待发送端发送数据
ds.receive(dp);
//3.解析数据
byte[] data = dp.getData();
int length = dp.getLength();
InetAddress address = dp.getAddress();
int port = dp.getPort();
System.out.println("接收到数据:" + new String(data, 0, length));
System.out.println("来自主机地址:" + address + "从端口号:" + port);
}
}
三、TCP通信协议与程序
3.1 定义与特点
TCP协议:传输控制协议(Transmission Control Protocol),也是传输层的一个主要协议。
- 面向连接:在传输数据之前,发送端和接收端需要建立逻辑连接,形成传输数据的通道。连接建立后,双方可以开始进行数据传输。每次连接的创建都需要经过"三次握手"的过程,以保证连接的可靠。
- 可靠传输:通过确认和重传机制来保证数据的可靠传输,不会出现数据包丢失、重复或乱序到达的情况。
- 面向字节流:TCP将数据看作是一连串无结构的字节流,发送方将字节流发送到接收方,接收方将其重新组装成完整的消息。
- 开销较大:由于需要建立连接、维护和终止连接,以及进行错误控制和流量控制等机制,TCP的开销相对较大。
3.2 程序
**Java中的TCP通信:**Java对于基于TCP协议的网络提供了良好的封装,使用Socket对象代表两端的通信端口,并通过Socket产生IO流进行网络通信。
Java为客户端提供了Socket类,为服务端提供了ServerSocket类。在TCP通信中,客户端通过创建Socket对象并连接到服务器端的ServerSocket对象来建立连接。连接建立后,双方可以通过IO流进行数据传输。
客户端:
java
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
//创建客户端对象
Socket socket = new Socket("127.0.0.1", 10086);
//从连接通道获取写出流
OutputStream outputStream = socket.getOutputStream();
//写出数据
outputStream.write("abc".getBytes());
//释放资源
outputStream.close();
socket.close();
}
}
服务端:
java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
//创建服务端对象
ServerSocket ss = new ServerSocket(10086);
//等待客户端连接
Socket socket = ss.accept();
//读取数据
InputStream inputStream = socket.getInputStream();
int data;
while ((data = inputStream.read()) != -1){
System.out.print((char) data);
}
System.out.println();
//释放资源
inputStream.close();
socket.close();
ss.close();
}
}
注意:
客户端传输数据如果为中文时,在服务端通过字节流读取数据时中文会显示乱码!!!因为中文在UTF-8字符编码中占三个字节,需要将服务端获取的字节流通过转换流转换成字符流。即:
java
//字节流读取中文会乱码,需要使用转换流转换成字符流,还可以使用缓冲流加快读取速度
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
四、TCP的三次握手与四次挥手
4.1 三次握手
三次握手是TCP连接建立的过程,主要目的是确保客户端和服务器之间能够可靠地通信。其过程如下:
第一次握手:
- 客户端(Client)向服务器(Server)发送一个连接请求报文段,其中包含一个随机数作为初始序列号(seq=x),并设置标志位SYN=1,表示希望建立连接。
- 此时,客户端从CLOSED状态进入SYN-SENT状态。
- 服务器由LISTEN状态向SYN-RCVD状态转换。
第二次握手:
- 服务器接收到客户端的请求后,向客户端发送一个确认报文段,其中包含确定的序列号(seq=y)和一个随机数作为确认号(ack=x+1),并设置标志位SYN=1和ACK=1,表示同意建立连接并确认客户端的序列号。
- 此时,服务器进入SYN-RCVD状态。
- 客户端接收到服务器的确认报文后,由SYN-SENT状态转换为ESTABLISHED状态。
第三次握手:
- 客户端接收到服务器的确认报文段后,再次向服务器发送一个确认报文段,其中包含确定的序列号和确认号(seq=x+1,ack=y+1),并设置标志位ACK=1,表示确认服务器的序列号并同意建立连接。
- 此时,服务器收到客户端的确认报文后,也从SYN-RCVD状态转换为ESTABLISHED状态。
- 至此,TCP连接建立完成,双方都可以开始传输数据。
4.2 四次挥手
四次挥手是TCP连接释放的过程,主要目的是确保双方都已经完成数据的传输并释放相关资源。其过程如下:
第一次挥手:
- 客户端想要关闭连接,发送一个FIN报文段给服务器,其中包含一个序列号(seq=u),并设置标志位FIN=1,表示希望断开连接。
- 此时,客户端从ESTABLISHED状态进入FIN-WAIT-1状态。
第二次挥手:
- 服务器接收到客户端的FIN报文段后,发送一个ACK报文段给客户端,其中包含确认号(ack=u+1),并设置标志位ACK=1,表示接收到了关闭请求。
- 此时,服务器进入CLOSE-WAIT状态,表示已经准备好关闭连接,但可能还有数据需要发送。
- 客户端接收到服务器的ACK报文后,进入FIN-WAIT-2状态。
第三次挥手:
- 服务器在发送完所有剩余数据后,也想要关闭连接,于是发送一个FIN报文段给客户端,其中包含序列号(seq=w,因为服务器在CLOSE-WAIT状态可能又发送了一些数据,导致序列号发生改变)和确认号(ack=u+1,这个确认号与第二次挥手时的相同,因为是在发送FIN报文段时重复确认),并设置标志位FIN=1和ACK=1。
- 此时,服务器进入LAST-ACK状态。
第四次挥手:
- 客户端接收到服务器的FIN报文段后,发送一个ACK报文段给服务器,其中包含确认号(ack=w+1),并设置标志位ACK=1,表示确认接收到了服务器的FIN报文段并同意关闭连接。
- 此时,客户端进入TIME-WAIT状态,等待一段时间(通常是2个报文生存最大时长)以确保网络中没有任何遗留报文后,再关闭连接。
- 服务器接收到客户端的ACK报文后,立即关闭连接。
4.3 总结
- 三次握手确保了客户端和服务器之间能够可靠地建立连接,通过互相发送确认报文段来验证双方的接收能力。
- 四次挥手确保了双方都已经完成数据的传输并释放相关资源,通过互相发送FIN和ACK报文段来逐步关闭连接。
结语
通过对Java网络编程的学习,我们掌握了如何利用Java内置的类和方法来实现网络通信。无论是基于TCP的Socket编程,还是基于UDP的Datagram编程,都为我们提供了丰富的工具,使我们能够轻松地构建出功能强大且稳定的网络应用程序。
同时,我们也深刻理解了网络通信中的关键概念,如三次握手与四次挥手,这些概念不仅在网络编程中占据核心地位,更是理解TCP/IP协议栈工作原理的基础。这些协议确保了数据在网络中的可靠传输,为我们构建复杂的网络应用提供了坚实的保障。
因此,对于每一个有志于在IT领域发展的开发者来说,深入掌握Java网络编程无疑是一项极具价值且必要的技能。它不仅能够提升我们的技术能力,更能够为我们打开通往更广阔技术世界的大门。