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 对象。
尝试连接服务端socketpublic 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队列的处理就有点复杂了,分两种情况:
    1. 如果server端设置了sysctl_tcp_abort_on_overflow,那么server会发送rst给client,并删除掉这个链接。默认情况下是不会设置的。
    2. 如果没有设置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次挥手断开连接

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/57018.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SQL Server 2019数据库“正常,已自动关闭”

现象&#xff1a; SQL Server 2019中&#xff0c;某个数据库在SQL Server Management Studio&#xff08;SSMS&#xff09;中的状态显示为“正常&#xff0c;已自动关闭”。 解释&#xff1a; 如此显示&#xff0c;是由于该数据库的AUTO_ CLOSE选项被设为True。 在微软的官…

基于 Konva 实现Web PPT 编辑器(三)

完善公式 上一节我们简单讲述了公式的使用&#xff0c;并没有给出完整的样例&#xff0c;下面还是完善下相关步骤&#xff0c;我们是默认支持公式的编辑功能的哈&#xff0c;因此&#xff0c;我们只需要提供必要的符号即可&#xff1a; 符号所表达的含义是 mathlive 的command命…

电力系统IEC-101报文主要常用详解

文章目录 1️⃣ IEC-1011.1 前言1.2 101规约简述1.3 固定帧格式1.4 可变帧格式1.5 ASDU1.5.1 常见类型标识1.5.2 常见结构限定词1.5.3 常见传送原因1.5.4 信息体地址 1.6 常用功能报文1.6.1 初始化链路报文1.6.2 总召报文1.6.3 复位进程1.8.4 对时1.8.4.1时钟读取1.8.4.2时钟写…

适用于 vue react Es6 jQuery 等等的组织架构图(组织结构图)

我这里找的是 OrgChart 插件; 地址: GitHub - dabeng/OrgChart: Its a simple and direct organization chart plugin. Anytime you want a tree-like chart, you can turn to OrgChart. 这里面能满足你对组织架构图的一切需求! ! ! 例: 按需加载 / 拖拽 / 编辑 / 自定义 / …

基于STM32F407VGT6芯片----跑马灯实验

一、在STM32F407VGT6芯片中配置GPIO环境 对于一个跑马灯实验&#xff0c;首先&#xff0c;要了解的就是&#xff0c;芯片是如何构造出来的&#xff0c;设计GPIO引脚&#xff1a;根据原理图&#xff0c; PC4&#xff0c;PC5,PC6,PC7 为 LED 输出控制管脚&#xff0c;PE0 为蜂鸣…

机器学习面试笔试知识点-线性回归、逻辑回归(Logistics Regression)和支持向量机(SVM)

机器学习面试笔试知识点-线性回归、逻辑回归Logistics Regression和支持向量机SVM 一、线性回归1.线性回归的假设函数2.线性回归的损失函数(Loss Function)两者区别3.简述岭回归与Lasso回归以及使用场景4.什么场景下用L1、L2正则化5.什么是ElasticNet回归6.ElasticNet回归的使…

嵌套div导致子区域margin失效问题解决

嵌套div导致子区域margin失效问题解决 现象原因解决方法 现象 <div class"prev"></div> <div class"parent"><div class"child"></div><div class"child"></div> </div> <div cl…

cisco网络安全技术第3章测试及考试

测试 使用本地数据库保护设备访问&#xff08;通过使用 AAA 中央服务器来解决&#xff09;有什么缺点&#xff1f; 试题 1选择一项&#xff1a; 必须在每个设备上本地配置用户帐户&#xff0c;是一种不可扩展的身份验证解决方案。 请参见图示。AAA 状态消息的哪一部分可帮助…

低代码可视化-uniapp海报可视化设计-代码生成

在uni-app中&#xff0c;海报生成器通常是通过集成特定的插件或组件来实现的&#xff0c;这些插件或组件提供了生成海报所需的功能和灵活性。我们采用了lime-painter海报组件。lime-painter是一款canvas海报组件&#xff0c;可以更轻松地生成海报。它支持通过JSON及Template的方…

企业网站设计之网站版式设计

一个成功的企业网站不仅仅需要强大的技术支持&#xff0c;更需要合理而吸引人的版式设计。版式设计在网站建设中扮演着关键角色&#xff0c;直接影响用户体验和品牌形象。本文将探讨主题企业网站版式设计的关键要素。 一、清晰的信息结构&#xff1a; 一个主题企业网站应该具有…

STM32学习笔记---独立看门狗

目录 一、什么是独立看门狗 1、什么是看门狗 2、看门狗的原理 3、看门狗的作用 4、看门狗的分类 二、如何配置独立看门狗 1、独立看门狗框图 2、独立看门狗的相关寄存器 2.1 关键字寄存器 2.2 分频寄存器 2.3 重载值寄存器 2.4 状态寄存器 3、程序设计 4、独立看门…

零基础入门人工智能,如何利用AI工具提升你的学习效率?

在这个信息爆炸的时代&#xff0c;人工智能&#xff08;AI&#xff09;不仅是技术行业的热词&#xff0c;更是我们日常生活中不可或缺的部分。你是否也想过&#xff0c;如何更有效地学习和利用这些强大的AI工具来提升自己的学习效率&#xff1f;今天&#xff0c;我们将介绍六款…

【WRF工具】QGis插件GIS4WRF:根据嵌套网格生成namelist.wps文件

【WRF工具】QGis插件GIS4WRF:根据嵌套网格生成namelist.wps文件 准备:WRF嵌套网格QGis根据嵌套网格生成namelist.wps文件检查:根据namelist.wps绘制模拟区域ArcGIS Pro中绘制嵌套网络投影变换参考GIS4WRF 是一个免费且开源的 QGIS 插件,旨在帮助研究人员和从业者进行高级研…

【Hive】8-Hive性能优化及Hive3新特性

Hive性能优化及Hive3新特性 Hive表设计优化 Hive查询基本原理 Hive的设计思想是通过元数据解析描述将HDFS上的文件映射成表 基本的查询原理是当用户通过HQL语句对Hive中的表进行复杂数据处理和计算时&#xff0c;默认将其转换为分布式计算 MapReduce程序对HDFS中的数据进行…

玫瑰花HTML源码

HTML源码 <pre id"tiresult" style"font-size: 9px; background-color: #000000; font-weight: bold; padding: 4px 5px; --fs: 9px;"><b style"color:#000000">0010000100000111101110110111100010000100000100001010111111100110…

buuctf[湖南省赛2019]Findme1

解压得5个图片&#xff0c;其中图片1&#xff0c;高度不正常&#xff0c;使用下面脚本破解真实高度和宽度 import os import binascii import structcrcbp open("1.png", "rb").read() for i in range(1024):for j in range(1024):data crcbp[12:16] st…

维修数据屏:重塑热力公司运维管理新格局

在热力公司的运维管理中&#xff0c;高效的报修和维修流程是确保系统稳定运行的关键。随着科技的发展&#xff0c;维修数据屏的出现为热力公司的运维工作带来了重大变革。 一、传统热力运维面临的挑战 过去&#xff0c;热力公司在报修和维修方面存在诸多问题&#xff0c;给运维…

SpringCloud学习:Seata总结与回顾

SpringCloud学习&#xff1a;Seata总结与回顾 文章目录 SpringCloud学习&#xff1a;Seata总结与回顾1. Seata实战&#xff1a;测试2. Seate原理总结和面试题3. Seata总结与回顾4. 易混点 1. Seata实战&#xff1a;测试 测试问题 未启用分布式事务 若不使用分布式事务&#xf…

Greenhills学习总结

学习背景&#xff1a;近期参与xx项目过程中&#xff0c;遇到较多的关于代码集成编译的知识盲区&#xff0c;因此需要进行相关知识的学习和扫盲。 参考资料&#xff1a;GreenHills2017.7编译手册:本手册是GreenHills 2017.7.14版编译器的软件使用手册。该手册详细介绍了GreenHi…

Docker consul注册中心

一、consul 1.1、什么是服务注册与发现 服务注册与发现是微服务架构中不可或缺的重要组件。 起初服务都是单节点的&#xff0c;不保障高可用性&#xff0c;也不考虑服务的压力承载&#xff0c;服务之间调用单纯的通过接口访问。 直到后来出现了多个节点的分布式架构&#x…