当前位置: 首页 > java >正文

【Java】网络编程基础与聊天室架构分析

IP 和 端口号

IP 用于标识网络中的主机 , 是如计算机 , 路由器等网络层设备的地址 .

端口号用于标识主机上运行的具体进程或服务 , 是传输层的逻辑接口 .

常见的 IPv4 地址为 32 位长 , 通常写成点分十进制形式 , 如 192.168.1.100 . IPv4 地址范围从 0.0.0.0255.255.255.255 , 其中较为特殊的是 回环地址 127.0.0.1 , 表示当前设备本身 .

端口号为 16 位整数 . 取值范围 0 - 65535 , 其中 0 - 1023 为通常由操作系统保留的系统端口,1024 - 65535 为用户或动态分配的端口 .

IP 类似于主机的门牌号 , 确定访问网络的设备的具体地址 . 端口号类似于门牌上的门或信箱 , 用来区分该主机上的不同网络服务 .

TCP 和 UDP

TCP 是一种面向连接的可靠传输协议 . TCP 在传输前需要经过三次握手建立连接 , 传输过程中提供错误校验 , 重传 , 顺序控制 , 流量控制和拥塞控制 , 确保数据无差错 , 不丢失 , 不重复 , 按序到达 .

因此 TCP 适用于对数据完整性和准确性要求较高的场景 , 如文件传输 , 电子邮件 , Web 浏览等 . 由于功能开销大 , TCP 头部长度固定为 20 字节以上 , 传输成本较高 .

UDP 是一种无连接的不可靠传输协议 . UDP 发送数据前不建立连接 . 不提供重传和顺序保证 , 只尽最大努力交付 . UDP 头部只有 8 字节 . 开销较小 .

因此 UDP 适用于实时性要求高 , 对丢包容忍度较大的场景 , 如网络语音 , 视频会议 , 在线游戏 , DNS查询等 .

TCP 三次握手与四次挥手

TCP 使用三次握手的过程来建立可靠的连接 , 确保通信双方具备收发能力 , 并提前协商好消息传输的顺序 .

其流程如下 :

  1. 客户端向服务器发送连接请求 , 表明希望建立通信 .
  2. 服务器收到请求后 , 回复一个应答 , 表示同意连接 , 同时也发出自己的连接请求 .
  3. 客户端再回应一个确认消息 , 表示双方可以开始通信 .

至此 , 客户端和服务器之间的连接正式建立 , 可以开始稳定的数据传输 .

而连接的断开则采用四个步骤进行 , 目的是让双方都有机会完成剩余的数据发送 , 避免信息丢失 .

关闭流程如下 :

  1. 一方先提出断开连接的请求 .
  2. 另一方收到后 , 先表示收到了请求 , 但还会继续发送剩余的数据 .
  3. 等数据发完后 , 再向对方表示自己也准备断开 .
  4. 对方再确认一次 , 并稍作等待 , 确保断开消息被成功收到 , 然后才完全关闭连接 .

这种方式确保了通信中没有遗漏或突然中断 , 体现了 TCP 协议核心安全特性 .

Java TCP通信

Java 使用 ServerSocket 和 Socket 类实现 TCP 通信 . 服务器端代码示例 :

// Server.java - 服务器端
ServerSocket server = new ServerSocket(12345);      // 在端口12345监听
Socket client = server.accept();                   // 接受客户端连接
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));   // 读客户端消息
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); // 写出消息到客户端
String msg = in.readLine();    // 读取一行文本
out.write("服务器收到了: " + msg + "\n");
out.flush();

客户端代码示例 :

// Client.java - 客户端
Socket socket = new Socket("localhost", 12345);     // 连接到本机12345端口
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // 写消息到服务器
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));  // 读服务器回应
out.write("你好,服务器!\n");  
out.flush();
String response = in.readLine();  // 读取服务器回复
System.out.println("服务器说: " + response);

Java UDP通信

Java 使用 DatagramSocket 类和 DatagramPacket 类实现 UDP 通信。

发送数据的步骤包括 : 创建 DatagramSocket 和 DatagramPacket , 调用 send() 方法发送 , 最后关闭 Socket .

DatagramSocket ds = new DatagramSocket(); // 不指定端口,由系统随机分配
String str = "Hello UDP";
byte[] data = str.getBytes();
InetAddress addr = InetAddress.getByName("localhost");
int port = 12345;
DatagramPacket dp = new DatagramPacket(data, data.length, addr, port);
ds.send(dp);  // 发送数据包
ds.close();

接收数据的步骤包括 : 创建带监听端口的 DatagramSocket , 创建空的 DatagramPacket 作为接收容器 , 调用 receive() 方法接收数据包 , 从 DatagramPacket 中提取数据并解析 .

DatagramSocket ds = new DatagramSocket(12345); // 监听12345端口
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);  // 接收数据包(阻塞等待)
String received = new String(dp.getData(), 0, dp.getLength(), "UTF-8");
System.out.println("收到UDP消息: " + received);
ds.close();

该示例中,发送端通过DatagramPacket指定目标IP和端口发送消息;接收端通过绑定端口的DatagramSocket接收并解析数据包。

C/S 与 P2P

局域网聊天室中常用的两种架构是 **客户端-服务器 C/S 模式 **和 点对点 P2P 模式 .

C/S : 所有客户端都连接到一台中央服务器 , 客户端之间不直接通信 , 而是通过服务器转发信息 . 服务器负责维护在线用户列表 , 接收并广播消息给各客户端 , 实现群聊功能 .

该架构优点是实现简单 , 便于集中管理和广播消息 ; 缺点是服务器承载较大负载 , 存在单点故障风险 .

P2P : 每个节点既可作为客户端也可作为服务器 , 节点之间直接连接通信 . 常见的做法是让所有客户端先向中心服务器登记地址 , 获取其他在线节点列表 .请求通信时 , 客户端直接连接目标节点进行点对点聊天 . 登录后 , 客户端还会启动一个监听线程 , 接收其他节点的连接请求 .

P2P架构的优点是没有单点服务器 , 节点可以更灵活扩展 : 缺点是实现较为复杂 , 节点需要维护对等连接 , 有时需要处理网络地址转换等问题 .

特性C/S架构P2P架构
连接方式客户端主动连接服务器每个节点同时监听和主动连接其他节点
消息转发所有消息先汇集到服务器 , 由服务器转发给目标客户端或广播客户端之间直接通信 , 发送方直接将消息发给目标节点
连接维护服务器维护所有客户端的连接列表 , 统一管理上下线每个客户端维护自身与其他节点的连接或地址列表 , 节点自治

上述区别在代码实现上也有所体现 :

  1. C/S 服务器端使用 ServerSocket 接受客户端连接并保存客户端 Socket 列表 , 客户端统一与服务器的 Socket 读写消息 ; P2P 每个客户端除了作为客户端启动连接 , 也要打开 ServerSocket 监听端口以接收其它客户端的连接请求 , 节点既是客户端也是服务器 .

  2. 消息转发逻辑方面 , C/S 由服务器集中转发 , 而 P2P 是点对点直接发送 .

  3. 连接维护方面 , C/S 由服务器负责跟踪所有连接 . P2P 则需要各节点自行维护已连接对等方的信息 .

http://www.xdnf.cn/news/14297.html

相关文章:

  • HTML 从入门到起飞 · 系列合集:一站式学习不掉线
  • 构建多智能体(AI Agent)的高效协作平台——CrewAI探索
  • 基于CNN深度学习的小程序识别2-视频介绍下自取
  • 超子说物联网-MQTT_笔记1---通过EMQX搭建MQTT服务器
  • springboot项目启动报错:spring boot application in default package
  • React条件渲染之逻辑与和逻辑或详解
  • 第19篇:数据库中间件中的 SQL 分析与审计机制设计
  • 嵌入式硬件篇---常见电平标准
  • 【MPC】模型预测控制笔记 (3):无约束输出反馈MPC
  • flutter 项目配置Gradle下载代理
  • 以太网交换机交换表的建立
  • 使用VSCode开发FastAPI指南(二)
  • Kubernetes (K8S) 系统学习规划
  • 分布式数据库中间件-Sharding-JDBC
  • 性能优化 - 高级进阶: Spring Boot服务性能优化
  • C#设计模式之AbstractFactory_抽象工厂_对象创建新模式-学习
  • leetcode23-合并K个升序链表
  • Docker + PyFlink1.17 数据写入 MySQL
  • 技术选型指南:如何选择更适合项目的开源语言及其生态系统
  • ESP32 005 MicroPython I2S 实现音频传输与播放
  • 【数据可视化】Pyecharts-家乡地图
  • 从0开始学习语言模型--Day02-如何最大化利用硬件
  • Python OpenCV 4.10 库详解
  • 中科院医学1区Top:解放军医学院利用多组学+网络药理学+转录组测序联合解析苗药七角生白胶囊抗白细胞减少症的分子机制
  • AORSA编译指南
  • 探索niri:让你的Linux桌面布局无拘无束
  • HTTP 协议里15种请求方法及示例
  • 无监督 vs 有监督的本质区别
  • 数据赋能(256)——数据赋能业务——产品和服务变现
  • Linux 命令:source 用法详解与直接执行脚本的区别