JDK中socket源码解析
目录
1、Java.net包
1. Socket通信相关类
2. URL和URI处理类
3. 网络地址和主机名解析类
4. 代理和认证相关类
5. 网络缓存和Cookie管理类
6. 其他网络相关工具类
2、什么是socket?
3、JDK中socket核心Api
4、核心源码
1、核心方法
2、本地方法
3、linux是怎么处理链接的?
5、demo验证
建立连接
发送数据
断开连接
1、Java.net包
java.net包提供了一组用于网络编程的类,支持开发网络应用程序和处理网络通信。java.net包可以大致分为六个部分:
1. Socket通信相关类
这些类用于实现基于 TCP 和 UDP 协议的网络通信。
- Socket:实现客户端的 TCP 套接字,允许程序与远程主机建立连接并传输数据。
- ServerSocket:实现服务器的 TCP 套接字,用于监听客户端连接并接受连接请求。
- DatagramSocket:用于 UDP 套接字通信,通过不可靠的无连接数据报协议传输数据。
- MulticastSocket:扩展了 DatagramSocket,用于支持多播组通信,允许数据发送到多个接收者。
- SocketAddress:表示一个套接字地址,通常用于绑定到特定 IP 地址和端口。
- InetSocketAddress:表示 IP 地址和端口的组合,继承自SocketAddress 。
2. URL和URI处理类
这些类用于处理统一资源定位符(URL)和统一资源标识符(URI)。
- URL:表示一个 URL(统一资源定位符),用于定位网络资源。支持从指定的 URL 中读取和解析数据。
- URI:表示一个 URI(统一资源标识符),提供对 URI 的结构化处理。
- URLStreamHandler:处理 URL 的协议细节,通常用于为不同协议(如 http、ftp)定义特定的处理逻辑。
- URLConnection:表示到 URL 所引用的资源的通信链接,可以处理资源的获取和发送。
- HttpURLConnection:继承自URLConnection ,用于处理 HTTP 协议的 URL 连接,支持 HTTP 请求和响应。
- JarURLConnection:继承自URLConnection ,用于从 JAR 文件中获取资源。
3. 网络地址和主机名解析类
这些类用于表示 IP 地址和解析主机名。
- InetAddress:表示 IP 地址,可以通过主机名或 IP 地址来查找和操作网络主机。
- Inet4Address:表示 IPv4 地址。
- Inet6Address:表示 IPv6 地址。
- NetworkInterface:表示网络接口(如以太网接口),用于获取和操作本地计算机的网络接口。
4. 代理和认证相关类
这些类用于处理网络代理和认证功能。
- Proxy:表示网络通信中的代理设置,支持 HTTP 和 SOCKS 等代理类型。
- ProxySelector:用于选择代理服务器的策略,可以根据 URI 的类型来选择合适的代理。
- Authenticator:用于实现网络请求中的认证机制,允许为 HTTP 和 FTP 请求提供用户名和密码等凭据。
- PasswordAuthentication:表示用户名和密码对,用于 Authenticator 类中的认证操作。
5. 网络缓存和Cookie管理类
这些类用于处理缓存和 Cookie 的存储和管理。
- CookieHandler:用于管理 HTTP 协议中的 Cookie。
- CookieManager:具体的 Cookie 管理器实现,允许存储和检索 Cookie。
- CacheRequest:表示缓存系统中的请求,允许将资源写入缓存。
- CacheResponse:表示缓存系统中的响应,允许从缓存中读取资源。
6. 其他网络相关工具类
一些提供额外网络功能的工具类。
- DatagramPacket:用于表示数据报,包含通过 DatagramSocket 发送或接收的数据。
- IDN:提供对国际化域名的处理,允许将 Unicode 域名转换为符合 Punycode 编码的 ASCII 字符串。
- NetworkInterface:表示计算机上的网络接口,允许列举和操作网络接口。
- StandardProtocolFamily:定义标准协议族(如 INET 和INET6),用于套接字通信。
2、什么是socket?
一个IP地址和一个端口号称为一个套接字(socket)。此术语出现在最早的TCP规范(RFC793, Page 5)中。我们知道进程通信的方法有管道、命名管道、信号、消息队列、共享内存、信号量,这些方法都要求通信的两个进程位于同一个主机。但是如果通信双方不在同一个主机又该如何进行通信呢?在计算机网络中有一个tcp/ip协议族,使用tcp/ip协议族就能达到我们想要的效果,如下图所示:
socket就是提供了tcp/ip协议的抽象,对外提供了一套接口,同过这个接口就可以统一、方便的使用tcp/ip协议的功能了,使得我们可以在在不同的计算机或网络设备之间建立连接,允许数据的发送和接收。
3、JDK中socket核心Api
方法签名 | 作用 | |
构造函数 | public ServerSocket() | 创建未绑定的服务器套接字。稍后需要手动调用 bind() 来绑定到特定的端口。 |
public ServerSocket(int port) | 创建绑定到指定端口的服务器套接字,默认使用所有可用的网络接口(IP 地址)。 | |
public ServerSocket(int port, int backlog) | 创建绑定到指定端口的服务器套接字,并指定连接请求队列的最大长度 backlog 。 | |
public ServerSocket(int port, int backlog, InetAddress bindAddr) | 创建绑定到指定 IP 地址和端口的服务器套接字,指定 backlog 来定义连接请求的队列长度。 | |
public Socket(String host, int port)(客户端) | 创建一个客户端 Socket 并连接到指定的远程主机 host 和端口 port。 | |
绑定端口方法 | public void bind(SocketAddress endpoint)(客户端、服务端) | 将服务器套接字绑定到指定的 SocketAddress ,通常是 InetSocketAddress ,以监听特定端口。 |
public void bind(SocketAddress endpoint, int backlog) | 绑定到指定的 SocketAddress 并设置连接请求队列的最大长度 backlog ,队列满时拒绝新连接请求。 | |
监听客户端 | protected void listen(int backlog) | 将服务器套接字置于监听状态,backlog 参数指定允许等待连接的最大队列长度,超过该长度的连接请求将被拒绝。 |
接受客户端请求 | public Socket accept() throws IOException | 等待客户端的连接请求,接受成功后返回一个与客户端通信的新 Socket 对象。 |
尝试连接服务端socket | public void connect(SocketAddress endpoint, int timeout)(客户端) | 尝试连接到远程服务器指定的 SocketAddress 地址,timeout 参数指定连接超时时间(毫秒)。如果在超时时间内未能连接,则抛出异常。 |
数据输入输出 | InputStream getInputStream() | 获取 Socket 的字节输入流 |
OutputStream getOutputStream() | 获取 Socket 的字节输出流 | |
InetAddress getInetAddress() | 获取对端的 IP 地址 | |
InetAddress getPort() | 获取对端的端口号 |
4、核心源码
1、核心方法
客户端和服务端最重要的两个类是Socket和Server Socket,这俩一个代表tcp通信的客户端,一个代表服务端。从源码来看,ServerSocket和socket内部分别持有一个SocketImpl对象,用于将对应的方法代理给native方法。以服务端ServerSocket为例:
构造函数中通过调用setImpl()创建了一个SocketImpl实现类,所有的创建链接、读写数据系统交互的本地方法都是在实现类中调用,也就是将对应的方法代理给native方法。
public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {setImpl();if (port < 0 || port > 0xFFFF)throw new IllegalArgumentException("Port value out of range: " + port);if (backlog < 1)backlog = 50;try {bind(new InetSocketAddress(bindAddr, port), backlog);} catch(SecurityException e) {close();throw e;} catch(IOException e) {close();throw e;}} |
setImpl();方法在JDK17与JDK8中的实现方式不一样。JDK13之前使用的是PlainSocketImpl这个实现类(阻塞式 I/O),JDK 13后,Socket 的连接过程通过 NioSocketImpl 实现,采用了 NIO(非阻塞 I/O)技术来实现高效的网络连接和数据传输。具体可以参考:JDK13新特性
private void setImpl() {SocketImplFactory factory = ServerSocket.factory;if (factory != null) {impl = factory.createSocketImpl();} else {impl = SocketImpl.createPlatformSocketImpl(true);}}static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) { (默认传参false)if (USE_PLAINSOCKETIMPL) {return (S) new PlainSocketImpl(server);} else {return (S) new NioSocketImpl(server);}} |
创建对应的socket实现类以后,调用bind方法绑定端口与开启监听,真正的本地方法的调用都在:getImpl().bind(epoint.getAddress(), epoint.getPort())、getImpl().listen(backlog)中实现:
public void bind(SocketAddress endpoint, int backlog) throws IOException {if (backlog < 1)backlog = 50;try {@SuppressWarnings("removal")SecurityManager security = System.getSecurityManager();if (security != null)security.checkListen(epoint.getPort());getImpl().bind(epoint.getAddress(), epoint.getPort());getImpl().listen(backlog);bound = true;} catch(SecurityException e) {bound = false;throw e;} catch(IOException e) {bound = false;throw e;}} |
static void bind(ProtocolFamily family, FileDescriptor fd,InetAddress addr, int port) throws IOException{boolean preferIPv6 = isIPv6Available() &&(family != StandardProtocolFamily.INET);if (addr.isLinkLocalAddress()) {addr = IPAddressUtil.toScopedAddress(addr);}bind0(fd, preferIPv6, exclusiveBind, addr, port);} |
2、本地方法
JDK8源码中的路径:C:\jdk-8\src\solaris\native\java\net\PlainSocketImpl.cJNIEXPORT void JNICALL Java_java_net_PlainSocketImpl_socketBind(JNIEnv *env, jobject this,jobject iaObj, jint localport) {} |
3、linux是怎么处理链接的?
前面提到的核心Api中,有关建立socket连接的Api中都有一个参数叫做backlog,源码中这个参数如果不设置,系统默认值为50,那么这个参数到底是什么?
public ServerSocket(int port) throws IOException {this(port, 50, null);}public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {setImpl();} |
关于这个参数,只需要看懂下面这张图就明白了:
Linux内核协议栈为TCP连接管理使用两个队列,一个是SYN队列(半链接队列,用来保存处于SYN_SENT和SYN_RECV状态的请求),一个是accpetd队列(用来保存处于established状态,但是应用层没有调用accept取走的请求),这两个队列是内核实现的,当服务器绑定、监听了某个端口后,这个端口的SYN队列和ACCEPT队列就建立好了。如图,整个过程就是:
1. 当SYN包到达了服务器后,内核会把这一信息放到SYN队列(即未完成握手队列)中,同时回一个SYN+ACK包给客户端。
2. 一段时间后,客户端再次发来了针对服务器SYN包的ACK网络分组时,内核会把连接从SYN队列中取出,再把这个连接放到ACCEPT队列(即已完成握手队列)中。
3. 服务器在第3步调用accept时,其实就是直接从ACCEPT队列中取出已经建立成功的连接套接字而已。
那么问题来了,当这两个队列满了后,新的请求到达了又将发生什么?
- 对于SYN队列,若队列满,则会直接丢弃请求,即新的SYN网络分组会被丢弃,这个问题好解决,客户端接收不到回复,会再一次发送,然后服务端继续丢弃,知道队列有空闲的位置。而客户端如果一直接收不到回复,发几次之后就会停止。
- 对于ACCEPT队列的处理就有点复杂了,分两种情况:
-
- 如果server端设置了sysctl_tcp_abort_on_overflow,那么server会发送rst给client,并删除掉这个链接。默认情况下是不会设置的。
- 如果没有设置sysctl_tcp_abort_on_overflow ,server端只是标记连接请求块的acked标志,并且连接建立定时器,会遍历半连接表,重新发送synack,重复上面的过程,如果重传次数超过synack重传的阀值,会把该连接从半连接链表中直接删除。
5、demo验证
建立连接
- 1、服务端创建服务端套接字,并开启客户端监听与等待连接请求
- 2、客户端客户端套接字,尝试连接服务端
- 3、客户端调用private static native int connect0(boolean preferIPv6,
FileDescriptor fd,
InetAddress remote,
int remotePort) - 3次握手建立连接
发送数据
- 1、客户端调用OutputStreamWriter发送数据
- 2、服务端调用InputStreamReader接收数据
断开连接
- 手动使客户端关闭连接
- 4次挥手断开连接
相关文章:

JDK中socket源码解析
目录 1、Java.net包 1. Socket通信相关类 2. URL和URI处理类 3. 网络地址和主机名解析类 4. 代理和认证相关类 5. 网络缓存和Cookie管理类 6. 其他网络相关工具类 2、什么是socket? 3、JDK中socket核心Api 4、核心源码 1、核心方法 2、本地方法 3、lin…...
Ansible自动化运维项目实战指南
Ansible自动化运维项目实战指南 在当今快速发展的IT环境中,运维工作的复杂性和规模性日益增加,传统的手动运维方式已难以满足高效、可靠、可重复性的需求。Ansible作为一款开源的自动化运维工具,凭借其简单易用、无需代理、基于SSH的架构特性…...

MySQL【知识改变命运】10
联合查询 0.前言1.联合查询在MySQL里面的原理2.练习一个完整的联合查询2.1.构造练习案例数据2.2 案例:⼀个完整的联合查询的过程2.2.1. 确定参与查询的表,学⽣表和班级表2.2.2. 确定连接条件,student表中的class_id与class表中id列的值相等2.…...
Java学习教程,从入门到精通, Java 基础语法(4)
1、Java 基础语法 一、Java 简介与开发环境搭建 Java 简介:Java 是一种面向对象的编程语言,具有跨平台、安全、稳定等特点。Java 主要应用于企业级应用、Android 应用开发、大数据处理等领域。开发环境搭建:搭建 Java 开发环境需要安装 JDK…...

反编译工具-Jclasslib的使用,与Java方法调用的探索
这里写目录标题 前言IDEA下查看字节码的两种方法使用idea自带的插件工具安装插件 为什么没有看出方法调用关系原因分析工厂举例 知识补充语言java可移植性 总结 前言 画时序图的时候,我想验证下方法的调用是否写的正确。方法调用不仅涉及到程序的基本逻辑流程&#…...

力扣 简单 876.快慢指针
文章目录 题目介绍题解 题目介绍 题解 class Solution {public ListNode middleNode(ListNode head) {ListNode slow head, fast head;while(fast ! null && fast.next ! null){slow slow.next;fast fast.next.next;}return slow;} }...

FineReport 计算同比增长
1、数据库查询 SELECTt1.年,t1.月,t1.总金额 AS 同期金额,t1.仓库名称,t2.总金额 AS 上期金额 FROMtest t1LEFT JOIN test t2 ON ( t1.年 t2.年 1 ) AND t1.月 t2.月 AND t1.仓库名称 t2.仓库名称2、配置字段 月份字段加后缀 月 数据列加后缀 计算同比增长率 if(LEN(B3)0 …...

从0开始深度学习(12)——多层感知机的逐步实现
依然以Fashion-MNIST图像分类数据集为例,手动实现多层感知机和激活函数的编写,大部分代码均在从0开始深度学习(9)——softmax回归的逐步实现中实现过 1 读取数据 import torch from torchvision import transforms import torchv…...
如何利用OpenCV和yolo实现人脸检测
在之前的blog里面,我们有介绍OpenCV和yolo的区别,本文就人脸检测为例,分别介绍下OpenCV和yolo的实现方式。 OpenCV实现人脸检测 一、安装 OpenCV 首先确保你已经安装了 OpenCV 库。可以通过以下方式安装: 使用包管理工具安装&…...

015集——c# 实现CAD excel交互(CAD—C#二次开发入门)
第一步:添加引用 程序集—>扩展 namespace WindowsFormsApp2 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){}private void 获取当前excel_Click(object sender, EventArgs e…...

【计网笔记】以太网
经典以太网 总线拓扑 物理层 Manchester编码 数据链路层 MAC子层 MAC帧 DIX格式与IEEE802.3格式 IEEE802.3格式兼容DIX格式 前导码(帧开始定界符SOF) 8字节 前7字节均为0xAA第8字节为0xAB前7字节的Manchester编码将产生稳定方波,用于…...

Java 入门基础篇14 - java面向对象思想以及特性
学习目标: 一、目标 面向对象思想类和对象对象的创建和使用属性和方法封装 开始学习: 二、编程思想 2.1 什么是编程思想 做人有做人的原则,编程也有编程的原则。这些编程的原则,就叫做编程思想。 2.2 面向过程和面向对象 二…...

第15篇:网络架构优化与综合案例分析
目录 引言 15.1 网络性能优化的方法与工具 15.1.1 带宽管理与流量控制 15.1.2 负载均衡 15.1.3 缓存优化 15.2 网络故障的排查与解决 15.2.1 常用的网络故障排查工具 15.2.2 网络故障排查案例 15.3 网络安全架构的综合设计案例 15.3.1 企业网络安全架构的要求 15.3.…...

UI自动化测试实战
补充:Selenium主要用于Web页面的自动化测试,它可以模拟用户的各种操作,如点击、输入、滚动等,来测试网页的功能。而Appium是一个开源的移动端自动化测试工具。 一、自动化测试实战章节 自动化测试流程测试用例编写项目自动化测试…...

东方智者颜廷利:以哲学思想促进世界和谐与无私奉献
【本社讯】在全球化的今天,东方智慧与哲学思想正逐渐成为促进世界和谐与理解的重要力量。近日,祖籍齐鲁大地山东济南的东方智者颜廷利以其深邃的哲学思想和对人类社会的深刻洞察,引起了国际社会的广泛关注。 颜廷利,一位致力于哲学研究与实践的智者,他的思想跨越古今,融合了东…...

基于 springboot vue停车场管理系统 设计与实现
博主介绍:专注于Java(springboot ssm 等开发框架) vue .net php phython node.js uniapp 微信小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设,从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不…...
如何验证ssl私钥和证书是否匹配?
从证书(CRT)文件提取公钥 openssl x509 -in server.crt -pubkey -noout | openssl sha256从证书签名请求(CSR)文件提取公钥 openssl req -in server.csr -pubkey -noout | openssl sha256从私钥(KEY)文件…...

MongoDB的基本操作
🌷数据库准备 🎈Mongoshell 1.在指定目录下创建mongodb文件夹、其子文件log和data以及mongodb.log cd /home/ubuntu mkdir -p mongodb/data mkdir -p mongodb/log touch mongodb/log/mongodb.log 执行mongodb命令启动mongdb服务 mongod --dbpath /h…...
spring mvc后端实现过程
文章目录 一、Spring mvc1、controller1.1、LoginController011.2、LoginController 2、service2.1、LoginService2.1、LoginInimplements 3、dao3.1、LoginMapper3.1、LoginMapper.xml 4、实体类 一、Spring mvc 1、controller 控制器层、处理用户的请求和响应, …...
102005
import os os.environ["CUDA_VISIBLE_DEVICES"] "0" # 设定使用的 GPUimport tensorflow as tf from dataset import generate_data import numpy as np from model import enhancednet# 检查 TensorFlow 是否可以识别 GPU gpus tf.config.list_physica…...

多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...

LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...

Spring AOP代理对象生成原理
代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】,这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...