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 工作机制的更多相关文章

  1. 磁盘IO工作机制

    磁盘IO工作机制 ref: <深入分析java web 技术内幕> by:许令波 几种访问文件的方式 文件读取和写入的 IO 操作都是调用操作系统提供的接口,因为磁盘设备是由操作系统管理的 ...

  2. Java IO工作机制分析

    Java的IO类都在java.io包下,这些类大致可分为以下4种: 基于字节操作的 I/O 接口:InputStream 和 OutputStream 基于字符操作的 I/O 接口:Writer 和 ...

  3. Linux-磁盘及网络IO工作方式解析

    PIO与DMA 有必要简单地说说慢速I/O设备和内存之间的数据传输方式. PIO我们拿磁盘来说,很早以前,磁盘和内存之间的数据传输是需要CPU控制的,也就是说如果我们读取磁盘文件到内存中,数据要经过C ...

  4. [I/O]javaI/O工作机制

    摘要:IO问题可以说是当今web应用中面临的主要问题之一.因为在这个数据爆发的时代,海量的数据在网络到处流动,而在这个过程中都会涉及IO问题,可以说IO问题已经成为web应用的瓶颈之一.如何优化?以此 ...

  5. Java I/O 工作机制(一) —— Java 的 I/O 类库的基本架构

    Java 的 I/O 类库的基本架构 Java 的 I/O 操作类在包 java.io 下,有将近 80 个类. 按数据格式分类: 面向字节(Byte)操作的 I/O 接口:InputStream 和 ...

  6. 2 深入分析 Java IO的工作机制(一)

    大部分Web应用系统的瓶颈都是I/O瓶颈 2.1 Java的I/O类库的基本架构 Java的I/O操作类在包java.io下,大概有将近80个类,这些类大概可以分成如下4组. 基于字节操作的I/O接口 ...

  7. 深入分析 Java I/O 的工作机制--转载

    Java 的 I/O 类库的基本架构 I/O 问题是任何编程语言都无法回避的问题,可以说 I/O 问题是整个人机交互的核心问题,因为 I/O 是机器获取和交换信息的主要渠道.在当今这个数据大爆炸时代, ...

  8. 深入分析Java I/O的工作机制 (一)

    此篇博客看至许令波的深入分析javaWeb内幕书籍, 此篇博客写的是自己看完之后理解的重点内容,加一些理解,希望对你有帮助. 1.Java的I/O类库的基本架构 先说一下什么是类库:可以说是类的集合, ...

  9. Java I/O 的工作机制浅析

    I/O 问题可以说是当今互联网 Web 应用中所面临的主要问题之一,因为当前在这个海量数据时代,数据在网络中随处流动.这个流动的过程中都涉及到 I/O 问题,可以说大部分 Web 应用系统的瓶颈都是 ...

随机推荐

  1. cheat.sh在手,天下我有

    前言 作为程序员需要了解的东西有很多,日常编码和写脚本脱离不开各式语言与 Linux 命令.为了记住一些杂乱的或不被经常使用的知识点,我们迫切需要一个"小抄"/备忘录,小抄内容多了 ...

  2. 16_Android的数据存储_ SharedPreference、XML和JSON

    1. Android读写首选项 1.1 SharedPreferences SharedPreferences 是一种轻型的数据存储方式,它的本质是基于XML文件存储Key-Value键值对数据,通常 ...

  3. 总结一下 php连接oracle,完全可用。

    大致有两种方法 第一种 开启php_pdo_oci扩展,一般集成环境都会有这个扩展. 这个东西还是比较简单的,去官网查看吧 http://php.net/manual/zh/book.pdo.php ...

  4. MapReduce怎么优雅地实现全局排序

    思考 想到全局排序,是否第一想到的是,从map端收集数据,shuffle到reduce来,设置一个reduce,再对reduce中的数据排序,显然这样和单机器并没有什么区别,要知道mapreduce框 ...

  5. 第9.10节 Python中IO模块其他文件操作属性和方法简介

    本文中所有案例中的fp都是使用open函数打开文件返回的一个文件对象,为了节省篇幅,大部分没有提供文件打开的代码. 一. 文件是否关闭的属性 属性名:closed 功用:判断文件是否关闭 示例: &g ...

  6. Python中文文件处理中涉及的字符编码及字符集

    在现在的互联网,字符编码是互联网信息交互的一个重要基础,各种语言都有支持信息编码的机制,Python也不例外.Python除了字符编码之外,对于字节码和字符串两种类型有严格区分,字符串是本地可以读取的 ...

  7. Python模块学习遇到的问题

    Python使用import导入模块时报ValueError: source code string cannot contain null bytes的解决方案 Python使用import导入模块 ...

  8. 第 5篇 Scrum 冲刺博客

    一.站立式会议 1.站立式会议照片 2.昨天已完成的工作 售货员页面功能 3.今天计划完成的工作 添加登录系统账号密码数据库模块 继续对商品销售部分进行编码 职工管理页面 4.工作中遇到的困难 ①页面 ...

  9. Devpress (DxReport)使用ReportDesigner (一) 基本功能

    1. Devpress (DxReport)编辑 (1) 新建一个XtraReport. (2) 在报告上点右键添加元素:   元素说明: (1) 其中有报告头,报告尾,页头,页尾,组头,组尾,详细. ...

  10. 题解-CF708D Incorrect Flow

    题面 CF708D Incorrect Flow 给一张网络流图,可能有流量不守恒或者流量超过容量的情况,求最少的将某条边流量或容量 \(\pm 1\) 的操作次数使得网络流图正确. 数据范围:\(1 ...