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

Java 网络编程学习笔记

Java网络编程学习笔记

网络编程概述

CS和BS架构

  • CS(Client Server):客户端-服务器架构

  • BS(Browser Server):浏览器-服务器架构

网络编程三要素

要素描述
IP设备在网络中的地址,唯一标识
端口应用程序在设备中唯一的标识
协议数据在网络中传输的规则,如TCP/UDP

IP地址

IPv4

  • 32位,点分十进制表示

  • 范围:0.0.0.0 - 255.255.255.255

  • 特殊地址:127.0.0.1(localhost,本地回环地址)

IPv6

  • 128位,冒分十六进制表示

  • 范围:0:0:0:0:0:0:0:1 - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff

  • 0位压缩表示法:FF01:0:0:0:0:0:0:1101 → FF01::1101(只能使用一次)

常用命令

  • ipconfig:获取本机IP

  • ping:测试IP是否可用

端口

  • 端口号范围:0-65535(2字节表示)

  • 0-1023:系统保留端口,不能被程序使用

  • 一个端口号只能被一个应用程序使用

协议

网络协议分层

层级协议示例
应用层HTTP, FTP, DNS, SMTP, Telnet
传输层TCP, UDP
网络层IP, ICMP, ARP
物理链路层MAC

UDP协议

  • 用户数据报协议(User Datagram Protocol)

  • 面向无连接通信协议

  • 特点:速度快,有大小限制(一次最多发送64KB数据),数据不安全,易丢失数据

TCP协议

  • 传输控制协议(Transmission Control Protocol)

  • 面向连接的通信协议

  • 特点:速度慢,没有大小限制,数据安全

InetAddress类

InetAddress类表示互联网协议(IP)地址,封装IP地址。

常用方法

  • static InetAddress getByName(String host):确定主机名称的IP地址

  • String getHostName():获取此IP地址的主机名

  • String getHostAddress():返回文本显示中的IP地址字符串

import java.net.InetAddress;
import java.net.UnknownHostException;
​
public class NetDemo {public static void main(String[] args) throws UnknownHostException {// 获取InetAddress对象InetAddress address = InetAddress.getByName("10.102.160.242");System.out.println(address);System.out.println("主机名: " + address.getHostName()); // DESKTOP-PB9U58VSystem.out.println("IP地址: " + address.getHostAddress()); // 10.102.160.242}
}

注意

  • InetAddress.getByName()方法根据提供的主机名进行网络查询或DNS解析

  • 如果提供的是IP地址字符串,则不会进行任何网络查询或DNS解析

UDP协议

UDP单播发送示例

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
​
public class SendMessageDemo {public static void main(String[] args) throws IOException {// 创建DatagramSocket对象DatagramSocket ds = new DatagramSocket();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入发送的数据:");String str = sc.nextLine();if ("886".equals(str)) {break;}byte[] bytes = str.getBytes();InetAddress address = InetAddress.getByName("127.0.0.1");int port = 10086;// 打包数据DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);// 发送数据ds.send(dp);}// 释放资源ds.close();}
}

UDP单播接收示例

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
​
public class ReceiveMessageDemo {public static void main(String[] args) throws IOException {// 创建DatagramSocket对象DatagramSocket ds = new DatagramSocket(10086);byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);while (true) {// 接收数据(阻塞方法)ds.receive(dp);// 解析数据byte[] data = dp.getData();int length = dp.getLength();String hostName = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();System.out.println("ip为" + hostName + "的" + name + "说:" + new String(data, 0, length));}}
}

注意事项

  • 接收端需要绑定端口,且端口必须与发送端指定的端口一致

  • receive()方法是阻塞的,程序会等待发送端发送消息

单播、组播和广播

组播地址

  • 组播地址范围:224.0.0.0 - 239.255.255.255

  • 其中224.0.0.0 - 224.0.0.255为预留的组播地址

广播地址

  • 广播地址:255.255.255.255

组播发送示例

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
​
public class SendMessageDemo1 {public static void main(String[] args) throws IOException {// 创建MulticastSocket对象MulticastSocket ms = new MulticastSocket();// 创建DatagramPacket对象String data = "hello,udp";byte[] bytes = data.getBytes();InetAddress address = InetAddress.getByName("224.0.0.1");int port = 10086;DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, port);// 发送数据ms.send(dp);// 释放资源ms.close();}
}

组播接收示例

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
​
public class ReceiveMessageDemo1 {public static void main(String[] args) throws IOException {// 创建MulticastSocket对象MulticastSocket ms = new MulticastSocket(10086);// 将当前本机添加到224.0.0.1组中InetAddress address = InetAddress.getByName("224.0.0.1");ms.joinGroup(address);// 创建DatagramPacket对象byte[] bytes = new byte[1024];DatagramPacket dp = new DatagramPacket(bytes, bytes.length);// 接收数据ms.receive(dp);// 解析数据byte[] data = dp.getData();int length = dp.getLength();String ip = dp.getAddress().getHostAddress();String name = dp.getAddress().getHostName();int port = dp.getPort();System.out.println("数据是: " + new String(data, 0, length));System.out.println("发送端的ip是: " + ip);System.out.println("发送端的端口是: " + port);System.out.println("发送端的名称是: " + name);// 释放资源ms.close();}
}

TCP协议

TCP通信程序

  • 通信的两端各建立一个Socket对象

  • 通信之前要保证连接已经建立

  • 通过Socket对象产生IO流来进行网络通信

TCP服务器示例

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
​
public class Server {public static void main(String[] args) throws IOException {// 先启动服务端// 1.创建ServerSocket对象ServerSocket ss = new ServerSocket(10086);// 2.监听客户端连接(阻塞方法)Socket accept = ss.accept(); // 返回客户的连接对象// 3.从连接通道中获取输入流读取数据InputStream in = accept.getInputStream();InputStreamReader isr = new InputStreamReader(in);int b;while ((b = isr.read()) != -1) {System.out.print((char) b);}// 4.释放资源in.close();ss.close();}
}

  1. TCP 三次握手与四次挥手

    三次握手(建立连接)

    TCP 使用三次握手(3-way Handshake)机制来建立一条可靠的连接。这个过程确保客户端和服务器都准备好进行数据传输,并同步序列号。

    详细过程:

    步骤详解:

    1. 第一次握手(SYN)

      • 客户端发送一个 TCP 数据包,其中:

        • SYN 标志位设置为 1(表示请求建立连接)

        • 随机生成一个序列号 Seq = J

      • 客户端进入 SYN-SENT 状态

      • 目的:客户端告诉服务器"我想建立连接,我的初始序列号是 J"

    2. 第二次握手(SYN+ACK)

      • 服务器收到请求后,发送回应数据包,其中:

        • SYNACK 标志位都设置为 1

        • 随机生成自己的序列号 Seq = K

        • 确认号 Ack = J + 1(表示期望收到从 J+1 开始的数据)

      • 服务器进入 SYN-RCVD 状态

      • 目的:服务器说"我同意连接,我的初始序列号是 K,已收到你的请求"

    3. 第三次握手(ACK)

      • 客户端收到回应后,发送确认数据包,其中:

        • ACK 标志位设置为 1

        • 序列号 Seq = J + 1

        • 确认号 Ack = K + 1

      • 客户端进入 ESTABLISHED 状态

      • 服务器收到后也进入 ESTABLISHED 状态

      • 目的:客户端确认"收到你的同意,我们现在可以开始通信了"

    为什么需要三次握手?

    • 防止已失效的连接请求突然传到服务器:网络延迟可能导致旧的连接请求晚到达,二次握手无法区分新旧请求

    • 同步双方序列号:确保双方都知道对方的初始序列号,为可靠传输做准备

    • 双向确认:确保客户端和服务器都有发送和接收能力

    四次挥手(断开连接)

    TCP 使用四次挥手(4-way Handshake)机制来终止连接。这个过程允许双方优雅地关闭连接,确保所有数据都传输完毕。

    详细过程:

    步骤详解:

    1. 第一次挥手(FIN)

      • 主动关闭方(假设是客户端)发送 FIN 数据包:

        • FIN 标志位设置为 1

        • 序列号 Seq = U(等于已传送数据的最后一个字节的序号加1)

      • 客户端进入 FIN-WAIT-1 状态

      • 目的:客户端告诉服务器"我的数据发完了,准备关闭连接"

    2. 第二次挥手(ACK)

      • 服务器收到 FIN 后,发送 ACK 回应:

        • ACK 标志位设置为 1

        • 确认号 Ack = U + 1

        • 序列号 Seq = V

      • 服务器进入 CLOSE-WAIT 状态

      • 客户端收到后进入 FIN-WAIT-2 状态

      • 目的:服务器说"收到你的关闭请求,但我可能还有数据要发给你"

    3. 第三次挥手(FIN)

      • 服务器完成数据发送后,发送 FIN 数据包:

        • FIN 标志位设置为 1

        • 序列号 Seq = W(可能等于 V 或 V+已发送数据量)

        • 确认号 Ack = U + 1

      • 服务器进入 LAST-ACK 状态

      • 目的:服务器说"我的数据也发完了,准备关闭连接"

    4. 第四次挥手(ACK)

      • 客户端收到 FIN 后,发送 ACK 回应:

        • ACK 标志位设置为 1

        • 序列号 Seq = U + 1

        • 确认号 Ack = W + 1

      • 客户端进入 TIME-WAIT 状态,等待 2MSL(最大报文段生存时间)后关闭

      • 服务器收到 ACK 后立即关闭连接

      • 目的:客户端确认"收到你的关闭请求,现在我们都关闭吧"

    为什么需要四次挥手?

    • 半关闭状态:TCP 连接是全双工的,允许一方在发送完数据后关闭发送通道,同时保持接收通道开放

    • 确保数据完整传输:给予被动方时间处理完剩余数据后再完全关闭

    • 可靠终止:确保双方都知道连接已终止,避免悬空连接

    为什么需要 TIME-WAIT 状态?

    • 防止旧连接数据包干扰:等待 2MSL 确保所有本连接的数据包都在网络中消失

    • 保证可靠终止:如果最后一次 ACK 丢失,服务器会重发 FIN,客户端可以再次响应

    实际编程中的注意事项:

    • 作为服务器,应该正确处理连接关闭,调用 close() 方法

    • 客户端应该优雅关闭连接,而不是强制终止

    • 网络编程中需要注意处理各种异常关闭情况

    • 对于频繁建立关闭的连接,需要注意端口重用问题(SO_REUSEADDR)

补充说明

DatagramSocket细节

  • 绑定端口:通过指定端口往外发送数据

  • 空参构造:从所有可用端口中随机获取一个进行使用

  • 带参构造:指定端口进行绑定使用

DatagramPacket参数

  • byte buf[]:字符数组

  • int length:字符数组的长度

  • InetAddress address:目标地址

  • int port:目标端口

注意事项

  1. TCP通信需要先启动服务端,再启动客户端

  2. UDP接收端需要绑定端口,且端口必须与发送端指定的端口一致

  3. receive()accept()方法是阻塞的,程序会等待数据或连接

  4. 使用完网络资源后需要及时关闭,释放资源

http://www.dtcms.com/a/372030.html

相关文章:

  • kerberos详解
  • 【数据结构基础习题】-1- 数据结构基本操作
  • OSCP - Proving Grounds - Catto
  • Claude Code 使用指南
  • RabbitMQ 持久化
  • matrix-breakout-2-morpheus靶机渗透
  • 学习结构体
  • Docker 容器 OOM:从资源监控到JVM调优的实战记录
  • TypeORM、Sequelize、Hibernate 的优缺点对比:新手常见 SQL 与 ORM 踩坑总结
  • 企业级低代码平台的条件函数系统设计:从复杂到极简的架构演进
  • ICCV-2025 | 中科院自动化所世界模型助力具身导航!NavMorph:连续环境中的视觉语言导航自演化世界模型
  • ChatGPT 协作排查:Node.js 内存泄漏的定位与修复
  • Cannot resolve plugin org.apache.maven.plugins:maven-site-plugin:3.1.0
  • 备战 2025 软考系统架构师
  • RabbitMQ 重试机制 和 TTL
  • 人工智能竞赛提高mAP的方法
  • 深度学习——残差神经网络案例
  • LeetCode 刷题【68. 文本左右对齐】
  • Day23_【机器学习—集成学习(5)—Boosting—XGBoost算法】
  • 基于飞算JavaAI的在线图书借阅平台设计与实现(深度实践版)
  • fps:AI系统
  • 强化学习入门:从零开始实现Dueling DQN
  • 做事总是三分钟热度怎么办
  • 图像形态学
  • C++运算符重载——函数调用运算符 ()
  • 分布式系统——分布式数据库的高扩展性保证
  • C++ 并发编程:异步任务
  • 四、神经网络的学习(中)
  • OPENPPP2 —— IP标准校验和算法深度剖析:从原理到SSE2优化实现
  • 梅花易数:从入门到精通