文笔者将与大家分享:TCP/IP协议族、HTTP、TCP、UDP、Socket、状态码等的基础知识。
互联网,顾名思义,就是互相连接,形成网络。其中的关键是“联网”,从技术上看,联网就是通信。
那么,通信的过程是怎么样的呢?使用浏览器访问网页,是最为常见的通信方式,我们也以访问网页为例,查看一个完整的通信过程。
我们在浏览器中输入一个 URL,回车之后便会在浏览器中观察到页面内容,实际上这个过程经过了很多个步骤。
互联网的的关键是通信,而通信的关键则是通信协议。
说句题外话,有段时间,联想5G投票事件闹得沸沸扬扬,除了民族情绪,更多的还是对通信协议的争夺,谁掌握了通信协议,谁就掌握了通信的核心。
计算机之间的通信协议是TCP/IP协议族,通信协议定义了通信的基本问题。
比如:由哪一边先发起通信、使用哪种语言进行通信、数据传输顺序是怎么样的、怎样结束通信等规则,这些规则称为协议(protocol)。通过这些协议,不同的计算机、手机甚至智能手表之间都可以互相通信。
“族”的意思是很多种协议,比如TCP、UDP、IP、FTP、HTTP、ICMP等都属于 TCP/IP 族内的协议。这些协议本身又可以划分为不同的层次,大致可以分为4层,分别是:应用层、传输层、网络层和链路层。
当然也有不同的划分方式,不同的划分方式大同小异,没有本质的区别。
1)应用层
应用层负责传送各种最终形态的数据,是直接与用户打交道的层,典型协议是HTTP、FTP等。
2)传输层
传输层负责传送文本数据,传输层有两个性质不同的协议,分别是 TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Data Protocol,用户数据报协议)。
3)网络层
网络层负责分配地址和传送数据,主要协议是IP协议。
IP地址(Internet Protocol Address)是指:互联网协议地址,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异,用来在网络中标记一台电脑的一串数字,比如192.168.1.1。
4)链路层
链路层向该层用户提供透明的和可靠的数据传送基本服务。
透明性是指:该层上传输的数据的内容、格式及编码没有限制,也没有必要解释信息结构的意义;可靠的传输使用户免去对丢失信息、干扰信息及顺序不正确等的担心。
你可能会感到奇怪,为什么要层次化呢?
数据是如何流动传输?
数据发送的时候依次经过应用层、传输层、网络层、链路层,之后通过光纤等硬件传送给接收端。
接收端的链路层接收到数据,并依次通过网络层、传输层、最终到达应用层,进行数据处理。
首先,作为发送端的客户端在应用层(HTTP 协议)发出的 HTTP请求(比如想要访问http://www.baidu.com),并生成HTTP数据。
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)是用于服务器传输超文本到本地浏览器的传送协议。HTTP是TCP/IP协议族的一部分,属于应用层的面向对象的协议,由于其简捷、快速的方式,受到了广泛的应用。
HTTP协议工作于客户端-服务端架构上,客户端向服务器发送所有请求,服务器根据接收到的请求后,向客户端发送响应信息。
HTTP协议具有以下特点:
TCP(transport control protocol,传输控制协议)是面向连接的、可靠的流协议。
流就是指不间断的数据,你可以把它想象成排水管中的水流。
面向连接,是指发送数据之前必须在两端建立连接。建立连接,为数据的可靠传输打下了基础。
可靠的意思是信息不会丢失,当一台计算机想要与另一台计算机通讯时,两台计算机之间的通信需要畅通且可靠,这样才能保证正确收发数据。比如:查收电子邮件的时候,有时候差一个字,意思可能就不一样了,所以要保证每一个字都能够接收到。
在技术实现上,TCP为了保证报文传输的可靠,就给每个包一个序号,序号也保证了传送到接收端实体的包的按序接收。接收端接受到数据之后,也会向发送端发送一个确认的信息(Acknowledgement ,ACK)。如果发送端在一定时间内没有收到接收端返回的ACK,那么发送端会重新发送数据,保证通信的可靠性。
UDP(user datagram protocol,用户数据报协议)与TCP协议一样用于处理数据包,是一种无连接,面向消息的,提供高效率服务的协议。
UDP是面向无连接的协议, UDP不需要在发送数据前进行建立连接,想发数据就可以开始发送了。有时候,接收端还没有准备好,发送端就开始发送数据了!
UDP也没有数据拆分和编号操作,一股脑直接发送过去了。特别是在网络传输状况较差的时候,发送端只顾着发送数据,接收端可能压根没有接受到数据。
但UDP这样做也有好处,就是传输速度快,TCP在传输之前要建立连接,传输过程中还要编号。接收端接收到所有编号之后,重新组装成信息,需要花费不少时间,在对时间较高的场景,这样做明显会带来较长的时延。
所以,UDP常用在对实时性较高的通信领域,比如:视频会议,这些情况对实时性要求较高,即使丢失了一些数据,也不影响接受信息。
TCP提供面向连接的可靠服务 ,UDP提供无连接的不可靠的服务。对数据准确性要求高,速度可以相对较慢的,可以选用TCP,对实时性要求高的场景可以使用UDP。
除了TCP/IP,我们可能也会听说过Socket。
Socket(套接字) 是对 TCP/IP 协议的封装,Socket 只是个接口(API)不是协议,通过 Socket 我们才能使用 TCP/IP 协议。
创建 Socket 接口的时候,需要指定传输层协议,可以是 TCP 或者 UDP,当用 TCP 连接,该Socket就是个TCP连接,反之亦然。
服务器响应客户端请求的时候,会返回HTTP状态码(HTTP Status Code)。状态码是表示服务器响应状态的3位数字代码,表示访问请求已经被服务器接收、理解并接收。
状态码可以分为下面5类:
下面是几个比较常见的状态码。
1)200:OK
请求已成功,出现此状态码是表示正常状态。
2)403:Forbidden
服务器已经理解请求,但是拒绝执行它,通常是服务器文件权限设置导致,比如:用户无权访问。
3)404:Not Found
用户最常见的状态码是404,即请求失败,通常是访问的资源在服务器中不存在。用户没有找到自己需要的资源,给用户的体验很不好,自定义404错误页面是提高用户体验的常见做法。
当用户访问的资源不存的时候,不是直接返回404,而是指向一个设计好的html 文件,有些网站甚至会为404设置个小游戏,作为彩蛋。
比如:游戏公司暴雪的404网页延续了其冷酷的设计,一张被锤子砸得面目全非的网页告诉用户:你真的走错路了。
我们去中国电信、中国联通、中国移动办理宽带网络的时候,带宽通常是10M、20M,但安装完成后,下载速度却可能只有1M/s,远远达不到所说的10M。是运营商欺骗了我们么?带宽、网速是什么,又有什么关系呢?
比特是信息的最小单位,1字节=8比特,1字节/秒=8比特/秒。因此, 10M带宽=1.25MB/s网速,1M带宽=0.125MB/s=128KB/s,运营商提供的10M网络,转换成网速也就是1.25M/s,跟我们日常的体验相符,这也算是运营商的“小诡计”了。
对普通用户而言,10M的宽带,每个月的上网费用就要几十块钱。不只是对普通用户,带宽成本对互联网公司而言同样是巨大的成本,特别是对于各大视频网站而言,带宽成本是非常巨大的运营成本。
根据阿里云提供的数据,按流量计费,要0.8元/G,一部电影通常在2G左右,下载一部电影就需要 1.6元,这个数据看起来可能不大,但考虑到用户规模,数据就会变得很大了。如果有100万个用户,每个用户每天看一部电影,每天的带宽成本可能就有160万元,这也是视频网站难以盈利的重要原因。
为了减低带宽成本,互联网公司也是想尽办法,比如:百度网盘会对非会员限速,巨大的带宽成本是百度网盘这么做的重要原因。
面对用户对限速的质疑,百度网盘回应,“作为一款免费的云存储产品,每年的服务器成本和带宽成本是硬伤啊。百度网盘存活着为广大用户提供免费的空间内存已经是一笔需每年持续支出的高额成本。除此之外,还有服务成本和带宽成本,宝宝们虽然已经为家里的网络网速买过单,但是当宝宝们打开百度网盘上传和下载文件时,我们还需要为这些文件传输时的带宽进行支付,用户文件传输时带宽越大我们需要支付的费用越高”。
即使是财大气粗的百度公司,也要考虑到昂贵的带宽成本,带宽成本始终是高流量网站需要面对的问题。
提高下载速度就要增加带宽,增加带宽,运营成本也随之提高;如果不增加带宽,下载速度就会降低,用户体验很差。
有没有什么办法可以解决成本和下载速度之间的矛盾呢?
P2P是个好主意,这里的P2P不是互联网金融的P2P,而是点对点(peer to peer)通信的网络技术。P2P依赖网络中参与者的计算能力和带宽,而不是把依赖都聚集在较少的几台服务器上,互联网金融的P2P借鉴了这个技术概念。
定义有些拗口,我们举个例子就明白了。
传统下载方式是从服务器端下载文件到客户端,由于是从一台服务器下载,服务器所提供的带宽是一定的,因此下载人越多速度越慢。假设服务器的带宽是100M,即12500kb/s。有100台客户端连接,那么每一台的带宽就是125kb/s,难怪下载速度这么慢!
为了避免服务端带宽的限制, P2P下载应运而生。与传统下载不同,P2P下载是用户越多,下载越快,这是因为P2P用的是一种共享的方式提供下载。
我们可能也会听说过BT,BT全名叫”BitTorrent”, BT和P2P有些差别,P2P指的是数据的一种传送方式,而BT是应用这种方式的软件。但我们大多数人接触较多的都是P2P,这里就用P2P直接使用P2P代指P2P和BT了,请读者知晓。
我们以迅雷下载为例,说明P2P的下载过程。
通过P2P下载,在不增加服务器带宽的时候,却能提高下载速度!网络真奇妙!
本文由@李艳宾 原创发布于人人都是产品经理,未经许可,禁止转载
题图来自Unsplash, 基于CC0协议
车仪表盘指示灯亮或闪速,这是在提醒驾驶人员你的汽车存在某种故障,每次启动汽车前大家一定要注意检查一下自己的仪表盘。仪表盘的指示灯太多,可能很多车主都不了解每个指示灯代表的意思。小编曾经有给大家介绍过汽车仪表盘指示灯图解,如下小编将马上为大家收集汽车故障灯标志图解、汽车故障灯大全。请各位车主对号入座。
汽车故障灯标志图解
自动变速器报警信号灯、未啮含”PARK“、自适应前照灯系统故障
自适应前照灯系统关闭、系统信息指示灯、防盗启动锁止系统指示灯
定速巡航控制指示灯、智能卡式遥控钥匙系、定速巡航主指示灯
智能钥匙系统警告灯、巡航设置指示灯、牵引力关闭指示灯
燃油经济性指示灯、AFS(自适应前照灯)、电子驻车制动系统警告
踩制动/离合踏板指示灯、点火警告灯、sos呼叫警告灯
汽车需要维修警告灯、换挡杠不可设置P档指示灯、换挡杠不可设置P档指示灯
电子方向盘锁止警告灯、空调滤清器故障灯、灯泡损坏故障灯
灯泡损坏故障灯、灯泡损坏故障灯、灯泡损坏故障灯
灯泡损坏故障灯、服务期限指示灯、服务有效指示灯
发动机转速低指示灯、发动机转速高指示灯、自适应弯道灯故障指示灯
巡航控制指示灯、车辆维修警示灯、超声波倒车辅助指示灯
盲区监测指示灯、传动系统警告灯、前向碰撞预警提示灯
车道保持指示灯、升档提示灯、燃油表/加油口盖位置
电子节气门控制指示灯、变速箱过热警告灯、DBC下坡制动控制
ABC主动车身控制、空气滤清器更换警告灯、挂车接合器故障灯
车身太低警告灯、车辆正被升起指示灯、燃油滤清器警告灯
车钥匙指示灯、车门未关闭警告灯、无法检测到钥匙指示灯
冷却液液位过低警告灯、夜市功能指示灯、夜市功能指示灯
胎压指示灯、燃油不足警告灯、动力蓄电池故障指示灯
运动模式指示灯、车距警告灯、遥控器电量低警告灯
遥控器警告灯、发动机动力部分损失、发动机排放系统警告灯
刹车温度过高警告灯、HDC坡道车速控制、车外温度指示灯
车窗防夹功能指示灯、无窗防夹功能指示灯、自适应大灯系统故障灯
自动手刹指示灯、安全带/安全气囊警告灯、发动机舱盖打开指示灯
刹车片磨损指示灯、转向阻力系统故障灯、水温报警指示灯
发动机预热指示灯、驻车制动与制动油位、发动机防盗锁止系统
乘客侧气囊指示灯、前排安全带指示灯、电子转向系统警告灯
转向系统警告灯、乘客侧气囊指示灯、VSA(车辆稳定控制)
VSA车辆稳定控制、发动机电子防盗指示灯、燃油液位低警告灯
保持模式指示灯、灯泡损坏指示灯、巡航控制指示灯
前雾灯指示灯、前照明指示灯、远光灯指示灯
后雾灯指示灯、换挡指示灯、行李箱盖未关闭指示灯
车门未关闭指示灯、后窗加热指示灯、EBD电子制动力分
驻车辅助指示灯、智能进入和启动系统、超速档关闭指示灯
坡道起步辅助警告灯、霜冻警示灯、霜冻警示灯
胎压低警告灯、信息指示灯、转向指示灯
可调空气悬架指示灯、可调空气悬架指示灯、清洗液液位低故障灯
清洗液液位低故障灯、光线/雨量传感器故障灯、钥匙不在车内提示灯
灯泡损坏指示灯、自动变速箱油温警告灯、钥匙在车外警告灯
动力转向警告灯、安全指示灯、VSC车辆稳定控制
低水温指示灯、防滑指示灯、VDC车身动态稳定
乘客安全带提示灯、制动系统警告灯、ESP车身稳定控制
EPS电子转向助力、转向锁止系统故障灯、发动机启动系统故障灯
发动机机油量警告灯、低压轮胎位置指示灯、手动变速器换挡指示灯
燃油滤清器警告灯、TCS牵引力控制系统、TCS牵引力控制系统
轮胎压力监测指示灯、柴油颗粒滤清器指示灯、转速限制功能指示灯
发动机机油有位指示灯、机油感应器指示灯、车窗雨刮器指示灯
减震器调节指示灯、拖车牵引装置指示灯、拖车转向灯指示灯
钥匙未在车内指示灯、钥匙未被识别指示灯、车道保持辅助系统指示灯
驾驶员疲劳提示指示灯、限速警告指示灯、遥控钥匙电量低指示灯
下坡行驶辅助指示灯、发动机关闭指示灯、发动机未被关闭指示灯
制动踏板未踩下指示灯、车辆保养提示灯、ABC主动车身控制
DTC和DSC指示灯、四驱系统警告灯、启动机系统指示灯
节能驾驶辅助指示灯、系统故障警告灯、动力电池过热警告灯
动力模式指示灯、EV驱动模式指示灯原文地址:http://www.pikacn.com/news/20161/3878.html
动力电池故障警告灯、动力蓄电池电量不足、电机及控制器过热指示灯
充电线链接指示灯、运行准备就绪指示灯、环保驾驶模式指示灯
发动机故障灯/尾气排放故障灯、EPC发动机功率控制、发动机系统故障指示灯
安全气囊警告灯、安全气囊警告灯、ABS防抱死系统指示灯
点火警告灯、点火警告灯、机油压力警告灯
车身稳定控制系统关闭、车身稳定控制系统指示灯、机油油位过低警告灯
安全带指示灯、燃油液位低警告灯、制动系统警告灯
期需要对公司的接口做线上的巡查监控,需要写一个脚本放到服务器上,定时运行脚本监测线上接口是否正常。
测试的接口不是HTTP协议,而是公司基于TCP协议开发的私有协议,因此不能直接用现成的一些接口测试工具,需要自己写代码来调用接口。
由于是私有协议,为了方便各业务项目进行通信,开发部门统一提供了一个TClient的jar包,底层使用了netty框架进行通信。调用方只需要按照协议的格式组装二进制的包,然后直接调用TClient的sendMessage方法就可以把数据发送出去,服务端处理完成后会异步回调,将响应数据返回给客户端。
脚本写完了,伪代码如下
public class Demo{
public void invoke(){
// 创建TClient并初始化
TClient client=new TClient(xxx);
// 组装接口数据包
Data data=new Data(xxx);
// 发送数据
Response res=client.sendMessage(data);
// 检查结果、存储结果、发送邮件
doSomething();
// 关闭client
client.close();
}
}
测试脚本中,每隔一分钟,创建一个Demo对象,调用invoke方法
Demo demo=new Demo();
demo.invoke();
脚本写好后在服务器上调试了下,接口返回数据正常,于是正式启动定时任务,观察了一会,运行一切正常,Perfect!
第二天早上到公司,登上服务器,查看昨晚脚本的运行情况,看了下日志。
打开日志我就震惊了,What?OutOfMemoryError!竟然内存泄漏了!
平常都是开发写bug时出现内存泄漏,今天终于轮到我自己了!
最后一条日志显示为下午17:17左右,也就是脚本大概运行了4小时后出现了内存泄漏。查看了下脚本进程,果然已经崩溃了,并且生成了一个dump文件。
经常做性能测试的同学,对内存泄漏都不陌生。内存泄漏总结来说就是JVM中存储的对象太多了,占满了全部内存空间,并且这些对象都是不可回收的。这样程序就不能再继续运行了,因为已经没有空间了。
举个例子,就好像去饭馆吃饭,饭馆里总是不断的有人进去,也有人出来。如果某天来了一帮人占满了饭店,并且赖着不走了,这样新顾客就进不来了,这个时候估计老板就崩溃了。
我先review了脚本的代码,没发现什么异常的问题。有的朋友可能会说,你不是每个1分钟创建一个Demo对象吗,运行这么长时间,会不会是Demo对象太多了?
其实并不会,写脚本的时候也考虑过这个问题,每次new Demo对象,因为上一次脚本已经执行完了,那么上一次的Demo对象就没有引用了,这样JVM在垃圾回收的时候会把上一次的Demo对象清理掉。这样并不会造成内存泄漏。
目光再回到服务器上,Java进程在崩溃时,自动生成了一个堆dump文件,如果已经发生了内存泄漏,可以分析这个dump文件,看看里面那些对象比较多,这样就能确定原因了。
一般在工作中分析内存泄漏时,可以把dump文件下载到本地,然后通过jvisualvm或者jprofiler打开文件,工具自动会分析哪些对象数量最多。
但是这个文件有1.3G,公司服务器下载有限速,想下载下来估计得等到7月7号testfan性能测试实战班开课那天了。
突然想到另外一个分析内存泄漏的工具MAT,之前都是在windows下使用MAT,其实MAT也有Linux版本,可以直接在服务器上对dump文件进行分析。
简单介绍下工具的使用方法:
1、 登录官网,下载Linux x86_64/GTK+版本
https://www.eclipse.org/mat/downloads.php
2、 解压后修改MemoryAnalyzer.ini配置文件,配置jvm参数(要比dump文件大)
3、 执行.mat提供的脚本
./ParseHeapDump.sh /home/xxx.hprof org.eclipse.mat.api:suspects
(/home/xxx.hprof是dump文件的路径)
4、 在xxx.hprof目录下,生成了java_pid32523_Leak_Suspects.zip压缩文件
5、 下载到windows下,解压,打开index.html
在分析页面中可以看到,io.netty.channel.nio.NioEventLoopGroup对象占用了JVM中61.36%的空间。其次是io.netty.buffer.PoolThreadCache对象,占用了21.38%。
看名字这俩对象都是netty框架中的类,在网上查了下资料,“NioEventLoopGroup”是netty中的一个线程池对象。
看页面上的统计,JVM中有1145个netty的线程池对象,这是什么操作?线程池不就一个就行了吗?为什么有这么多?
看到线程池对象,就想到会不会JVM线程方面有问题?因为脚本进程现在已经崩溃了,只能重新运行脚本,然后再对线程进行监控。
脚本运行过程中,通过监控jvm,发现old区确实在不断的缓慢增加,这样长时间跑下去,应该就会重现昨天晚上的问题。
执行jstack命令打印线程堆栈信息
jstack pid > thread.log
打开thread.log看了下,线程状态倒没啥问题,但是堆栈中有大量的nioEventLoopGroup线程,看编号有1000+,通过命令统计了下,确实有1000+个nioEventLoopGroup线程。
这个数量跟上面MAT工具分析的实例数量也差不多对应上了,现在问题基本上就确定了。也就是说在内存泄漏发生前,JVM中存在1000+个nioEventLoopGroup线程,每个线程创建了一个NioEventLoopGroup对象,因为线程池的特性,所以这些线程处于都是运行状态的。
并且在脚本运行过程中发现,这个nioEventLoopGroup线程并不是开始就是1000+,而是从0慢慢涨上来的。也就是说随着脚本的运行,慢慢积累上来的。
这个时候目光又回到了我的脚本中,虽然并不是因为我不断的new Demo对象造成了内存泄漏,但是肯定跟这个行为有关系,nioEventLoopGroup是netty框架用到的对象,于是就想到了代码中的TClient client=new TClient(xxx);
打开TClient的jar包看了下,在TClient的构造函数里,确实创建了一个nioEventLoopGroup对象
然后在connect方法中,使用了这个线程池对象bossGroup
现在基本上确定是什么原因了,如下:
a> 每隔1分钟,脚本会new一个Demo对象
b> Demo对象的invoke方法里又new了一个TClient对象
c> TClient对象内部在做netty连接初始化的时候,创建了NioEventLoopGroup线程池对象
虽然脚本中创建的Demo对象和TClient对象都会被JVM回收,但是可能是因为netty使用NioEventLoopGroup线程池和服务端建立了长连接,导致线程池对象并不会被回收。这样长时间跑下来,JVM中中的NioEventLoopGroup对象就会越来越多,最终导致了内存泄漏。
这么来看,还真是每次new Demo间接带来的影响。知道原因就好说了,Demo对象不能在每次运行的时候创建,而且放在类初始化的时候创建一个。无论脚本跑多少次,都只有一个NioEventLoopGroup对象了。
重新修改了下脚本,长时间运行监控了下,确实内存使用很稳定,没有出现内存泄漏的情况。
问题似乎是得到了解决,但是等等。我脑海中突然又想到另外一个问题,虽然我在脚本中每次都创建一个TClient对象,但是每次跑完后,都会调用TClient的close方法啊,close方法里应该会释放NioEventLoopGroup对象啊,难道没做吗?
打开TClient的jar包看了下close方法
在close方法中,确实把NioEventLoopGroup置为null了,对于一个普通的对象来说,只要对象引用为null,那么在下次JVM垃圾回收的时候,就会把这个对象回收掉。但是对于一个线程池对象来说,因为线程池中有活动线程存在,所以尽管置为null了,JVM也不会回收这个线程池。一般的线程池对象,都是通过shutdown方法来销毁线程池的。
查看了下netty的api文档,确实有shutdownGracefully方法(优雅关闭)
现在问题彻底搞清楚了,TClient的close方法中,只是简单的将线程池对象置为null,并没有进行shutdown操作,因此JVM并不能回收线程池对象。从而造成了,即便用户调用了close方法,其实资源也没有销毁,最终自然就会出现内存泄漏。
作为一个通用的工具包,内部的资源的释放,并不能靠调用者来保证。理论上来说,即便我每次都new TClient对象,只要我都关闭了。在业务层面来说,也是正常行为。不能让调用者必须缓存client对象,否则就会出现内存泄漏,这样是不合理的。
在跟相关开发沟通后,对代码做了修改,加上了shutdown方法,仍然用老的脚本进行测试,在长时间的运行后,内存依然保持正常。因此这个问题终于解决了。
最后总结一下
1、 此问题的根本原因是client包中close方法没有成功销毁资源
2、 理论上来说,重复创建大量对象并不会造成内存泄漏,但是如果代码中同时也创建了第三方包的对象,在不了解其实现细节的情况了,可能其内部会创建一些不可被回收的对象,这个时候就会有内存泄漏的风险。因此还是尽量的复用对象,减少内存泄漏问题的发生。
作 者:Testfan 北河
出 处:微信公众号:自动化软件测试平台
版权说明:欢迎转载,但必须注明出处,并在文章页面明显位置给出文章链接
*请认真填写需求信息,我们会在24小时内与您取得联系。