网络 IO 工作机制
ref: 深入分析 java web 技术内幕 2.3
两台计算机之间进行数据的传输需要经过很多步骤。首先有相互沟通的意向,然后还要有沟通的通道:通过电话还是面对面交流(物理链路)。最后,两个人说话的步调一致,明白什么时候自己说话,什么时候对方说话(通信协议)。本文简单介绍通信协议以及如何完成数据的传输。
TCP 状态转化
首先看看如何建立和关闭 TCP 连接,建立连接&传输过程中状态的变化见下图:

说明:
1、CLOSED:起始点,在超时或者连接关闭时进入此状态;
2、LISTEN:Server 端在等待连接时的状态,Server端为此要调用 Socket、bind、listen 等函数,就能进入此状态。这被称为被动打开(等待客户端来连接);
3、SYN-SENT:客户端发起连接,发送 SYN 给服务端。如果服务端不能连接,则直接进入 CLOSED 状态;
4、SYC-RCVD:与 3 对应,服务器端接口客户端的 SYN 请求,服务端由 LISTEN 状态进入 SYN-RCVD 状态。同时服务器端要回应一个 ACK,发送一个 SYN 给客户端;
另一种情况是,客户端在发起 SYN 的同时接收到服务器端的 SYN 请求,客户端会由 SYN-SEND 状态进入 SYN-RCVD 状态
5、ESTABLISHED:服务端和客户端在完成 3 次握手之后进入状态,说明已经可以传输数据了。
6、FIN-WAIT-1:主动关闭的一方,由状态5进入。具体动作是发送了 FIN 给对方;
7、FIN-WAIT-2:主动关闭的一方,在接受到对方的 FIN ACK 之后,进入此状态。由此不能再接受对方的数据,但是能够向对方发送数据。
8、CLOSE-WAIT:接收到 FIN 以后,被动关闭的一方进入此状态。具体动作是在接收到 FIN 之后,同时发送 ACK。
9、LAST_ACK:被动关闭的一方,发起关闭请求,有8状态进入此状态。具体动作是发送 FIN 给对方,同时在接收到 ACK 时进入CLOSED 状态;
10、CLOSING:两边同时发送关闭请求时,会由 FIN-WAIT-1 进入此状态。具体动作是接收到 FIN 请求,同时响应一个 ACK;
11、TIME-WAIT:进入这个状态比较复杂,也是我们最常见的一个连接状态,有3个状态可以转化为此状态:
- 由 FIN-WAIT-2 转换到 TIME-WAIT ,具体情况:在双方不同时发起 FIN 的情况下,主动关闭的一方在完成自身发起的关闭请求之后,接收到被关闭一方的 FIN 之后进入此状态。
- 由CLOSING 进入,具体情况:在双方同时发起关闭,都做了 发送 FIN 请求,同时接受到了对 FIN 的ACK 之后,这是就由CLOSING 状态进入此状态。
- 由 FIN-WAIT-1 状态进入,具体情况:同时接收到 FIN(对方) 和 ACK(本身发起的回应),它与 CLOSING 转换的区别在于本身发起的 FIN 的回应 ACK 先与对方对方的 FIN 请求到达,而由 CLOSING 转换则是 对方的 FIN 先于 ACK 到达。
简单理解:
- 无论是建立连接还是关闭,需要两边都发送请求,并且得到响应之后,连接才完成;
- 只不过,连接建立的时候,响应侧的响应和请求是同一次发出,而关闭是,响应和请求是分开发出。
除此之外,网络连接的状态也很重要,在排查问题的时候,网络连接处于什么状态,可以帮助我们判断问题到底在什么地方。
影响网络传输的因素
- 网络带宽:速度
- 距离:时间
- TCP 拥塞控制:我们知道 TCP 传输是一个“停-等-停-等”的协议,传输方和接受方需要步调一致,要达到步调一致就要通过拥塞控制来调节。
TCP 在传输的时候会设立一个“窗口”(BDP,bandwidth delay product),这个窗口的大小是有 带宽 和 RTT(Round-Trip time,数据在两端来回的时间,也就是响应时间)决定。具体公式是 带宽(b/s)* RTT(s)。通过这个值可以得出理论上最优的 TCP 缓冲区大小。linux 2.4 已经可以自动的调整发送端的缓冲区的大小,而到 linux 2.6.7 时,接收端也可以自动调整了。
JAVA Socket 的工作机制
Socket 是套接字的意思,它没有一个具体的实体,描述计算机之间完成相互通信的一种抽象功能。可以把Socket理解成一种交通工具,用于应用程序之间数据的传输。大部分情况下我们使用的都是基于 TCP/IP 的流套接字,它是一种稳定的通信协议。
网络中的主机A 的应用要能和网络中的主机B 上的应用程序进行通信,必须通过 Socket 建立连接,而建立 Socket 连接必须由底层 TCP/IP 来建立TCP连接。建立 TCP 连接需要底层 IP 来寻址网络中的主机。通过IP,我们可以找到目标主机,但是目标主机上可能有多个应用,如何和指定的应用进行通信呢?这就需要通过 TCP/UDP 的地址,也就是端口号来指定。这样我们就可以通过一个 Socket 示例来唯一代表一个主机上的应用的通信链路了。
建立通信链路
当客户端要和服务端通信时,客户端首先要创建一个 Socket 实例,操作系统将为这个 实例 分配一个没有被使用的本地端口号,并创建一个包含本地地址、远程地址和端口号的套接字数据结构,这个数据结构将一直保存在系统中,直到连接关闭。在创建 Socket 实例的构造函数正确返回之前,将要进行 TCP 的3次握手协议,TCP 握手协议完成后,Socket 实例对象将会创建完成,否则将抛出 IOException 错误。
与之对应的服务端将会创建一个 ServerSocket 实例,创建 ServerSocket 比较简单,只要指定的端口没有被占用,一般实例都会创建成功。同时操作系统也会为 ServerSocket 实例创建一个底层的数据结构,在这个数据结构中包含指定监听的端口号和包含监听地址的通配符,通常情况下都是“*”,表示监听所有的地址。之后调用 accept() 方法之后,将会进入阻塞状态,等待客户端的请求。
当一个新的请求来时,将为这个链接创建一个新 的套接字数据结构,该套接字数据信息包含的地址和端口信息正是请求源地址和端口。这个新创建的数据结构将会被关联到 ServerSocket 实例的未完成的连接数据结构列表中。需要注意的是,这时服务端与之对应的 Socket 实例并没有完成创建,而要等到与客户端的3次握手完成后,这个服务端的 Socket 实例才会返回,并将这个 Socket 实例对应的数据结构从未完成列表移动到已完成列表中。所以与 ServerSocket 所关联的列表中每个数据结构都代表与一个客户端建立的 TCP 连接。
数据传输
传输数据是我们建立连接的目的,下面简要介绍如何通过 Socket 传输数据。
**
当连接建立成功后,服务端和客户端都拥有了一个 Socket 实例,每个 Socket 实例都会有一个 InputStream 和 OutputStream,并通过这两个对象来交换数据。同时,我们知道网络IO 都是通过 字节流传输的,当创建 Socket 对象时,操作系统将会为 InputStream 和 OutputStream 分别分配一定大小的缓冲区,数据的写入和读取都是通过这个缓冲区完成的。写入端将数据写到OutputStream 对应的 SendQ 队列中,当队列填满时,数据将会被转移到另一端的 InputStream 的 RecvQ 队列中,如果这时 RecvQ 已经满了,那么 OutputStream 的 write 方法将会被阻塞,直到 RecvQ 有足够的空间容纳 SendQ 的数据。**
特别值得注意的是,这个缓冲区的大小以及写入端的速度和读取端的速度非常影响这个连接的数据传输效率,由于可能发生阻塞,所以网络IO和磁盘 IO 不同的是数据写入和读取还要有一个协调的过程,如果在两边同时传送数据可能会产生死锁。那么该如何避免这种情况,需要 NIO 来解决。
网络 IO 工作机制的更多相关文章
- 磁盘IO工作机制
磁盘IO工作机制 ref: <深入分析java web 技术内幕> by:许令波 几种访问文件的方式 文件读取和写入的 IO 操作都是调用操作系统提供的接口,因为磁盘设备是由操作系统管理的 ...
- Java IO工作机制分析
Java的IO类都在java.io包下,这些类大致可分为以下4种: 基于字节操作的 I/O 接口:InputStream 和 OutputStream 基于字符操作的 I/O 接口:Writer 和 ...
- Linux-磁盘及网络IO工作方式解析
PIO与DMA 有必要简单地说说慢速I/O设备和内存之间的数据传输方式. PIO我们拿磁盘来说,很早以前,磁盘和内存之间的数据传输是需要CPU控制的,也就是说如果我们读取磁盘文件到内存中,数据要经过C ...
- [I/O]javaI/O工作机制
摘要:IO问题可以说是当今web应用中面临的主要问题之一.因为在这个数据爆发的时代,海量的数据在网络到处流动,而在这个过程中都会涉及IO问题,可以说IO问题已经成为web应用的瓶颈之一.如何优化?以此 ...
- Java I/O 工作机制(一) —— Java 的 I/O 类库的基本架构
Java 的 I/O 类库的基本架构 Java 的 I/O 操作类在包 java.io 下,有将近 80 个类. 按数据格式分类: 面向字节(Byte)操作的 I/O 接口:InputStream 和 ...
- 2 深入分析 Java IO的工作机制(一)
大部分Web应用系统的瓶颈都是I/O瓶颈 2.1 Java的I/O类库的基本架构 Java的I/O操作类在包java.io下,大概有将近80个类,这些类大概可以分成如下4组. 基于字节操作的I/O接口 ...
- 深入分析 Java I/O 的工作机制--转载
Java 的 I/O 类库的基本架构 I/O 问题是任何编程语言都无法回避的问题,可以说 I/O 问题是整个人机交互的核心问题,因为 I/O 是机器获取和交换信息的主要渠道.在当今这个数据大爆炸时代, ...
- 深入分析Java I/O的工作机制 (一)
此篇博客看至许令波的深入分析javaWeb内幕书籍, 此篇博客写的是自己看完之后理解的重点内容,加一些理解,希望对你有帮助. 1.Java的I/O类库的基本架构 先说一下什么是类库:可以说是类的集合, ...
- Java I/O 的工作机制浅析
I/O 问题可以说是当今互联网 Web 应用中所面临的主要问题之一,因为当前在这个海量数据时代,数据在网络中随处流动.这个流动的过程中都涉及到 I/O 问题,可以说大部分 Web 应用系统的瓶颈都是 ...
随机推荐
- C语言实现聊天室(windows版本)
来源:微信公众号「编程学习基地」 目录 C语言聊天室 运行效果 分析设计 多线程 线程的同步 服务端设计 遇到的问题 C语言聊天室 基于 tcp 实现群聊功能,本项目设计是在windows环境下基于套 ...
- 五. Webpack详解
1. 什么是Webpack 1.1 引入 什么是webpack?这个webpack还真不是一两句话可以说清楚的. 我们先看看官方的解释:At its core, webpack is a static ...
- oracle 游标相关资料
游标 概述:游标是系统为用户开设的一个数据缓冲区,存放 SQL 语句的执行结果. 我们可以把游标理解为 PL/SQL 中的结果集,把游标当中一个集合 1:在声明区声明游标 cursor 游标名称 is ...
- 20191012_WMI中可以看到有打印机, 设备管理器中没有
开发过程中使用SELECT * FROM Win32_Printer 查看设备有一个备份打印机, 并且被设置为默认打印机了, 但是设备管理器中没有 解决方法: 使用系统自带的测试WMI (Windo ...
- 排序--HeapSort 堆排序
堆 排 序 堆排序.就是通过堆结构来排序.可以看之前写的http://www.cnblogs.com/robsann/p/7521812.html .关于堆的结构 堆排序先要使结构堆有序.所以要先使所 ...
- IAR编译出现Configuration is up-to-date.
IAR编译出现如下: Building configuration: SimpleBLECentral - CC2541EM Updating build tree... Configuration ...
- 第6章 Python中的动态可执行方法 第6.1节 Python代码编译
在介绍动态可执行方法前,本节先介绍一下Python代码编译有关的知识,因为部分内容和动态执行有些关联. 一. Python解释器的功能 Python虽然是解释型语言,但Python代码也是可编译 ...
- PyQt(Python+Qt)学习随笔:QTableWidget的currentItem、rowCount、columnCount等部件状态属性访问方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 老猿将QTableWidget表格部件中反映部件当前情况的一些方法归类为部件状态访问方法,包括部件的 ...
- ES6 代码转成 ES5 代码的实现思路是什么(来自github每日一题)
将代码字符串解析成抽象语法树,即所谓的 AST 对 AST 进行处理,在这个阶段可以对 ES6 代码进行相应转换,即转成 ES5 代码 根据处理后的 AST 再生成代码字符串 每日一题https:// ...
- 题解 洛谷 P5279 【[ZJOI2019]麻将】
这题非常的神啊...蒟蒻来写一篇题解. Solution 首先考虑如何判定一副牌是否是 "胡" 的. 不要想着统计个几个值 \(O(1)\) 算,可以考虑复杂度大一点的. 首先先把 ...