想让两台电脑互相传数据?想自己写个聊天工具?
网络编程听起来高大上,其实核心就三件事:IP 地址 + 端口号 + 协议 !📡
上篇先把网络基础和 UDP 协议吃透,手写聊天程序、广播和组播!
一、网络编程三要素 🔑
1.1 计算机网络是什么
实现不同地理位置、不同主机之间的数据交流,让多台计算机形成一个互联的系统。
1.2 核心三要素
地址(IP) → 定位哪台电脑 📍
↓
端口号(Port) → 定位哪个程序 🚪
↓
协议(Protocol) → 双方遵守的通信规则 📜
| 要素 | 作用 | 示例 |
|---|---|---|
| IP 地址 📍 | 唯一标识一台主机 | 192.168.1.100 |
| 端口号 🚪 | 标识主机上的应用程序 | 8080 / 3306 |
| 协议 📜 | 规定数据格式和传输规则 | TCP / UDP |
二、IP 地址------主机的「身份证」📍
2.1 IPv4 vs IPv6 对比
| 对比项 | IPv4 | IPv6 |
|---|---|---|
| 格式 | 4组十进制(0~255) | 8组十六进制(每组4位) |
| 示例 | 192.168.1.100 |
2001:0db8:85a3::8a2e:0370:7334 |
| 长度 | 32位(约43亿个) | 128位(沙子都能分到IP!) |
| 现状 | 已经不够用了 ⚠️ | 未来主流 ✅ |
2.2 IPv4 地址规则
格式:A.B.C.D(每组0~255)
前三个数字:子网编号(同一局域网)
最后一个数字:主机编号(同一子网内唯一)
特殊地址:
🏠 127.0.0.1 → 本机回环地址(localhost)
📡 255.255.255.255 → 广播地址
🏠 0 → 当前子网编号
2.3 InetAddress 类------Java 中的 IP 对象 📖
核心概念 :InetAddress 在 java.net 包中,没有公共构造方法,通过静态方法获取对象。
| 方法 | 功能 |
|---|---|
getLocalHost() |
获取本机 IP 对象 |
getByName(String host) |
根据主机名或 IP 字符串获取 |
getHostName() |
获取主机名 |
getHostAddress() |
获取 IP 地址字符串 |
java
import java.net.InetAddress;
public class Demo01 {
public static void main(String[] args) throws Exception {
// 1. 获取本机 IP 对象
InetAddress local = InetAddress.getLocalHost();
System.out.println("本机主机名:" + local.getHostName());
System.out.println("本机IP:" + local.getHostAddress());
// 2. 根据主机名获取(局域网内)
InetAddress remote = InetAddress.getByName("YR190814-KJQI");
System.out.println("远程主机:" + remote);
// 3. 根据 IP 地址获取
InetAddress byIp = InetAddress.getByName("192.168.26.23");
System.out.println("根据IP获取:" + byIp);
// 4. DNS 解析:根据域名获取 IP
InetAddress baidu = InetAddress.getByName("www.baidu.com");
System.out.println("百度:" + baidu);
}
}
💡 命令行:
ipconfig -all查看本机所有 IP 配置!
三、端口号------程序的「门牌号」🚪
3.1 端口号规则
- 范围 :
0 ~ 65535(2个字节,2^16) - 0~1023:系统保留端口,不建议使用 ⚠️
- 1024~49151:注册端口,可以自定义使用 ✅
- 49152~65535:动态端口,系统临时分配
3.2 常见默认端口
| 程序 | 端口号 | 说明 |
|---|---|---|
| HTTP | 80 | 默认不写端口就是 80 |
| HTTPS | 443 | 加密 HTTP |
| MySQL | 3306 | 数据库默认端口 |
| Tomcat | 8080 | Java Web 服务器 |
| Oracle | 1521 | Oracle 数据库 |
3.3 ⚠️ 端口冲突
同一台电脑上,两个程序不能使用同一个端口!
程序A 用了 8888 → 程序B 再用 8888 → 报错:端口已被占用!
解决:换端口号或关闭占用程序。
四、协议------通信的「交通规则」📜
4.1 TCP/IP 协议簇
应用层 HTTP、HTTPS、FTP ← 我们主要学这里 📋
↓
传输层 TCP、UDP ← 两种传输协议
↓
网络层 IP、ICMP
↓
物理层 网线、光纤、WiFi ← 硬件设备
4.2 UDP vs TCP 核心对比 💼
| 对比项 | UDP | TCP |
|---|---|---|
| 连接性 | 无连接 ❌ | 面向连接 ✅ |
| 可靠性 | 不可靠(可能丢包) | 可靠(确认机制)✅ |
| 效率 | 高 ✅ | 低 |
| 类比 | 发短信、寄信 📮 | 打电话 ☎️ |
| 场景 | 视频流、DNS、广播 | 网页、文件下载、聊天 |
| Java 类 | DatagramSocket |
Socket / ServerSocket |
五、UDP 编程------无连接的「快递员」📮
5.1 UDP 特点
- 无连接:发送前不用确认接收端是否准备好
- 不可靠:可能丢包,不保证送达
- 效率高:没有握手和确认开销
- 两端平等 :发送端和接收端都是
DatagramSocket
5.2 核心类
| 类名 | 作用 |
|---|---|
DatagramSocket |
UDP 套接字,既能发也能收 |
DatagramPacket |
数据包,封装要发送/接收的数据 |
5.3 DatagramSocket
| 构造方法 | 说明 |
|---|---|
DatagramSocket() |
创建发送端,端口随机 |
DatagramSocket(int port) |
创建接收端,指定端口 |
| 成员方法 | 说明 |
|---|---|
send(DatagramPacket p) |
发送数据包 |
receive(DatagramPacket p) |
接收数据包(阻塞) |
5.4 DatagramPacket ------ 数据的「快递盒」📦
发送用的构造:
java
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
// buf: 要发送的数据(字节数组)
// length: 要发送的长度
// address: 目标 IP 地址
// port: 目标端口号
接收用的构造:
java
DatagramPacket(byte[] buf, int length)
// buf: 接收数据的缓冲区
// length: 接收数据的最大长度
5.5 UDP 发送端代码
java
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDP_Sender {
public static void main(String[] args) throws Exception {
// 1. 创建发送端套接字(端口随机)
DatagramSocket ds = new DatagramSocket();
// 2. 准备要发送的数据
String msg = "江总,开房啊!";
byte[] data = msg.getBytes();
// 3. 封装数据包(指定目标地址+端口)
DatagramPacket dp = new DatagramPacket(
data, data.length,
InetAddress.getByName("192.168.26.23"), 6666
);
// 4. 发送数据
ds.send(dp);
System.out.println("发送完成!📮");
// 5. 关闭资源
ds.close();
}
}
5.6 UDP 接收端代码
java
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDP_Receiver {
public static void main(String[] args) throws Exception {
System.out.println("接收端启动,等待数据...📩");
// 1. 创建接收端套接字,指定监听端口
DatagramSocket ds = new DatagramSocket(6666);
// 2. 准备接收缓冲区
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
// 3. 接收数据(阻塞,直到收到数据)
ds.receive(dp);
// 4. 解析数据
String msg = new String(dp.getData(), 0, dp.getLength());
System.out.println("收到消息:" + msg);
// 5. 关闭
ds.close();
}
}
5.7 ⚠️ UDP 注意点
- 接收端必须先启动!虽然无连接,但没人监听就丢包了
receive()方法阻塞,直到收到数据- 发送端端口随机,接收端端口必须指定
- 数据最大长度:65,507 字节
六、UDP 聊天小程序 💬
6.1 发送端(带键盘录入 + 收回复)
java
import java.net.*;
import java.util.Scanner;
public class UDP_ChatSender {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("请输入(exit退出):");
String msg = sc.next();
// 发送消息
byte[] data = msg.getBytes();
DatagramPacket dp = new DatagramPacket(
data, data.length,
InetAddress.getLocalHost(), 9000
);
ds.send(dp);
if ("exit".equalsIgnoreCase(msg)) {
System.out.println("发送端退出!👋");
break;
}
// 接收对方回复
byte[] buf = new byte[1024];
dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
System.out.println("对方回复:" + new String(buf, 0, dp.getLength()));
}
ds.close();
}
}
6.2 接收端(收消息 + 回复)
java
import java.net.*;
import java.util.Scanner;
public class UDP_ChatReceiver {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(9000);
Scanner sc = new Scanner(System.in);
System.out.println("接收端启动,等待聊天...💬");
while (true) {
// 接收消息
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
String msg = new String(buf, 0, dp.getLength());
System.out.println("收到:" + msg);
if ("exit".equalsIgnoreCase(msg)) {
System.out.println("接收端退出!👋");
break;
}
// 回复消息
System.out.print("请输入回复:");
String reply = sc.next();
byte[] replyData = reply.getBytes();
DatagramPacket replyPacket = new DatagramPacket(
replyData, replyData.length,
dp.getAddress(), dp.getPort() // 从收到的包中获取发送方地址
);
ds.send(replyPacket);
}
ds.close();
}
}
七、UDP 广播 📡
7.1 什么是广播
向子网内所有主机 发送数据,广播地址必须是 255.255.255.255。
7.2 广播发送端
java
import java.net.*;
public class UDP_BroadcastSender {
public static void main(String[] args) throws Exception {
String msg = "江总真帅!";
byte[] data = msg.getBytes();
// ⚠️ 广播地址:255.255.255.255
DatagramPacket dp = new DatagramPacket(
data, data.length,
InetAddress.getByName("255.255.255.255"), 9999
);
DatagramSocket ds = new DatagramSocket();
ds.send(dp);
ds.close();
System.out.println("广播发送完成!📡");
}
}
7.3 广播接收端
java
import java.net.*;
public class UDP_BroadcastReceiver {
public static void main(String[] args) throws Exception {
DatagramSocket ds = new DatagramSocket(9999);
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
System.out.println("收到广播:" + new String(buf, 0, dp.getLength()));
ds.close();
}
}
八、UDP 组播 📡
8.1 什么是组播
向特定组 的主机发送数据,只有加入该组的成员才能收到(订阅模式)。
组播地址范围 :224.0.0.0 ~ 239.255.255.255
8.2 组播发送端
java
import java.net.*;
public class UDP_MulticastSender {
public static void main(String[] args) throws Exception {
String msg = "天成,也很帅!";
byte[] data = msg.getBytes();
// 组播地址(必须在 224.0.0.0 ~ 239.255.255.255)
DatagramPacket dp = new DatagramPacket(
data, data.length,
InetAddress.getByName("225.0.0.10"), 8888
);
// 发送端用 MulticastSocket(和普通 UDP 一样)
MulticastSocket ms = new MulticastSocket();
ms.send(dp);
ms.close();
System.out.println("组播发送完成!📡");
}
}
8.3 组播接收端(需加入组)
java
import java.net.*;
public class UDP_MulticastReceiver {
public static void main(String[] args) throws Exception {
MulticastSocket ms = new MulticastSocket(8888);
// ⚠️ 关键:加入组播组!
InetAddress group = InetAddress.getByName("225.0.0.10");
ms.joinGroup(group);
// 接收数据
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ms.receive(dp);
System.out.println("收到组播:" + new String(buf, 0, dp.getLength()));
ms.close();
}
}
8.4 💡 广播 vs 组播
| 对比项 | 广播 | 组播 |
|---|---|---|
| 地址 | 255.255.255.255 |
224.0.0.0 ~ 239.255.255.255 |
| 接收者 | 子网内所有主机 | 只有加入组的成员 |
| Java 类 | DatagramSocket |
MulticastSocket |
| 类比 | 大喇叭喊话 📢 | 微信群发消息 📱 |
本篇总结 📝
- 网络三要素 🔑:IP 地址(定位主机)+ 端口号(定位程序)+ 协议(通信规则)
- IP 地址 📍:IPv4(43亿个)vs IPv6(沙子都能分到),
InetAddress类获取 - 端口号 🚪:0~65535,1024+ 可自定义,常见端口要记(80/3306/8080)
- UDP 协议 📮:无连接、不可靠、效率高,
DatagramSocket+DatagramPacket - UDP 编程 📮:发送端端口随机、接收端端口固定、
receive()阻塞 - UDP 聊天 💬:死循环 + 键盘录入 + receive 收回复
- 广播 📡:地址
255.255.255.255,子网内所有主机都能收到 - 组播 📡:地址
224.x.x.x,需要joinGroup()加入组才能收到
🚀 下一篇预告:《四十三、网络编程(下)------TCP 编程与 HTTP 入门》------ 三次握手、文件上传、多线程并发服务器,理解网页背后的 HTTP 原理!
作者 :书源丶
发布平台:CSDN