ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java Nio(六)Java Nio实现高性能HTTP/HTTPS客户端

2021-06-21 19:01:21  阅读:249  来源: 互联网

标签:HTTP Nio 端口 地址 NAT IP地址 Java 数据包 连接


由以前的文章得知,http本质上是TCP连接,然后发送http约定的字节。既然是TCP那么TCP的一些限制也会影响http的性能,接下来介绍下我们访问网络的一些流程。

网络访问流程

IPv4/6

  我们现在常使用的IP地址是IPv4地址,由四组0-255的十进制数字组成,中间以小数点分隔。Internet上的每一台主机或者路由器都至少有一个IP地址。IP地址(IPv4地址,下文IP地址默认指IPv4)的长度是32位。被写成4组,每组8位,总数为2的32次方,大约43亿个。43亿IP地址假如全球每人分配一个IP就需要75亿。

  IPv6地址的二进制位数是128位,这128位地址通常被写成8组,每组为4个十六进制数的形式。ipv6是互联网协议的第六版,是下一代互联网协议。IPv6采用128位地址长度,其地址数量总数可达2的128次方个,当然这个还未普及。

  为了快速解决IP地址匮乏的这个问题,NAT技术诞生了。

NAT

  中文名唤作网络地址转换,诞生于IP地址匮乏的时代。

  NAT的基本思想是ISP(Internet服务提供商)为每个家庭或者公司分配一个IP地址,这个IP地址用作Internet流量的传输,也就是大家常说的外网IP地址或者公网IP地址。在客户网络的内部,每台计算机有唯一一个IP地址,即内网IP地址,这些地址主要用于路由内部流量。当一个数据包离开客户网络发送至其他ISP时,需要进行地址转换,把唯一的内网IP地址转换成外网的IP地址。

  这种地址转化使用IP地址的三个范围,这些地址已被声明私有化,任何内网中的设备可以任意使用这些地址,但是在这三个范围内的IP地址不允许出现在Internet(外网)上,这三个保留的地址范围是:
  10.0.0.0~10.255.255.255/8

  172.16.0.0~172.31.255.255/12

  192.168.0.0~192.168.255.255/16

  他们分别可以容纳16777216、1048576、65536台主机。一般家里用无线路由器,就用到了网络地址转换技术,我们连上wifi后分配的IP地址一般是以172或192为开头。学校或者大企业里面的网络可能会用到10开头的地址范围。

  NAT将内网外网划分好之后,是如何使内网的设备访问外网的呢?

  如下图,当计算机A在内网(假设IP为10.0.0.1)想去访问一个Internet上的网站S(假设IP地址为54.223.189.245)时,A的数据包需要先经过一个NAT盒子(NAT box),这个盒子先将A的IP源地址转换成外网的真实IP地址(假设IP为121.0.0.2),然后将转换后的数据包发送至Internet。

  于是问题来了,当网站S收到这个数据包后,会处理请求,并发送响应的数据包,然而这个数据包的目标地址是121.0.0.2(外网IP),数据包如何返回内网中的A呢?

  

  这里要先介绍一下源端口(Source Port)和目标端口(Destination Port)的概念。当一个进程希望与另一个进程建立TCP连接时,它把自己绑定到一个本机尚未被占用的TCP端口上,这个端口称为源端口,该TCP连接中所有入境的数据包都要被发送至这个端口。同时进程还需要提供一个目标端口,指明数据包到达远程主机后送至哪一个端口处理。每一个出境的TCP数据包都包括一个源端口和目标端口。

  举例来说,如下图,网站服务器S(IP地址为54.223.189.245)的HTTP服务运行在80端口上,公网上的计算机D(IP地址为121.141.56.23)想去访问网站S,于是把自己绑定到本机的33121端口上,并发送请求的数据包,这个数据包中就包含了计算机D的源端口33121和目标端口80。网站S收到请求后,发送响应的数据包,这个数据包中包含了服务器S的源端口80和目标端口3312。

  上面的例子是外网中的一台计算机访问一个网站。在内网中计算机发送的数据包同样存在着源端口和目标端口。NAT盒子做的事情就是对出入境数据包的端口进行修改。

  回到最初举的例子,假设内网计算机A(IP地址为10.0.0.1)发送的请求包的源端口是45421,目标端口是80,请求访问网站服务器S(IP地址为54.223.189.245)。

  当这个出境数据包经过NAT盒子时,其源地址被修改成公网的真实IP(121.0.0.2),源端口被修改一个索引值(假设为50002),这个索引值指向NAT盒子的地址转化表中的某一项,这一表项保存了计算机A的内网源地址和源端口。最后NAT盒子将重新生成的数据包发送出去。

  当网站S响应的入境数据包到达NAT盒子时,数据包经过处理,目的地址由公网IP(121.0.0.2)还原为计算机A的内网IP(10.0.0.1),目标端口由索引值(50002)还原为计算机A的源端口(45421)。还原后数据包可以正常的在内网路由。

  这个过程基本如下图所示。

网络访问的限制

  由上面可以看出,我们所有的内网ip都会映射到同一个外网ip,所有内网机器对外网的访问都要通过同一个外网ip。对于同一个外网ip来说,端口、socket存储等都是有限的,如果同一时间我们的请求越多,建立的TCP连接和NAT需要的资源也就越多,那么NAT的压力也越大,致使连接没有在规定的时间内收发数据,导致服务器断开连接,大量的请求超时或者其他异常。

提高性能的方法

1.连接池

  既然连接多会导致性能降低,那我们构造一个连接池不就得了。构造一个池子,维护连接数量,如果连接不足就创建连接,如果连接满了,就删除一个空闲连接然后再创建连接(删除策略可以优先删除最早的连接或者使用LRU策略),如果没有空闲连接就把请求添加到一个数组里面等待有空闲连接,保证连接数在一个上限下面。

2.复用连接  

  从HTTP/1.1起,默认开启了Keep-Alive,保持连接特性,客户端和服务器都能选择随时关闭连接,则请求头中为connection:close。简单地说,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的TCP连接。但是Keep-Alive不会永久保持连接,它有一个保持时间。我们可以用这个特性来实现连接复用(毕竟TCP三次握手也挺费时间的,尤其是https,ssl握手交换密钥需要的时间会更长)。只需要在上面的连接池里面构造一个以host和端口位key,连接数组为value的map即可,每次使用连接的时候先取同一目标地址和目标端口的空闲连接,取到后直接发送请求数据。如果没有再根据1里面的策略进行选取。

3.压缩算法

  访问那些返回的数据量大的地址时候,数据传输就成了影响性能的大头,毕竟大量的数据传输也需要很长时间,这个时候我们就可以通过压缩数据来将大数据变成小数据。比如前几篇文章提到过的gzip算法等。

 

具体的实现代码比较多,就不在这里写了,感兴趣的可以去github上 https://github.com/cxsummer/net-nio 看。

标签:HTTP,Nio,端口,地址,NAT,IP地址,Java,数据包,连接
来源: https://blog.csdn.net/cjc000/article/details/118087763

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有