http协议-html与http的区别

大白话:html协议是  保存信息的  文档协议,http协议 是 传输信息的 传输协议。

在Web服务中,信息一般是使用HTML格式以超文本和超媒体方式传送的,所使用的Internet协议是HTTP协议。

HTTP  意为超文本传输协议(全称是Hypertext Transfer Protocol)。是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示等(如文本先于图形显示)。这就是我们为什么在浏览器中看到的网址都是以“http://”开头的原因。

HTML  释为超文本标记语言(全称是Hypertext Markup Language),是用于WWW上文档的格式化语言。使用HTML语言可以创建文本文档,该文档可以从一个平台移植到另一个平台。HTML文件是带有嵌入代码(由标记表示)的ASCII文本文件,它用来表示格式化和超文本链接。HTML文件的内容通过一个页面展示出来,不同页面通过超链接关联起来。

 

网络原理-计算机网络详解-各类包长度及抓包分析

大白话:局域网 mtu 1500;Internet  mtu 576

对于UDP协议来说,整个包的最大长度为65535,其中包头长度是20字节(包括了伪首部:这个伪首部其实是属于ip头部的部分,里面有源ip地址和目标ip地址)所以UDP实际可用携带的最大数据是:65515字节长度。【udp协议里面:长度占了2个字节,16位。能够表示的范围是2^16-1 即 0-65515】

去除20字节的IP首部和8个字节的UDP首部,UDP数据报中用户数据的最长长度为65507字节。但是,大多数实现所提供的长度比这个最大值小。
我们将遇到两个限制因素。第一,应用程序可能会受到其程序接口的限制。socket API提供了一个可供应用程序调用的函数,以设置接收和发送缓存的长度。对于UDP socket,这个长度与应用程序可以读写的最大UDP数据报的长度直接相关。现在的大部分系统都默认提供了可读写大于8192字节的UDP数据报(使用这个默认值是因为8192是NFS读写用户数据数的默认值)。
第二个限制来自于TCP/IP的内核实现。可能存在一些实现特性(或差错),使IP数据报长度小于65535字节。
在SunOS 4.1.3下使用环回接口的最大IP数据报长度是32767字节。比它大的值都会发生差错。
但是从BSD/386到SunOS 4.1.3的情况下,Sun所能接收到最大IP数据报长度为32786字节(即32758字节用户数据)。
在Solaris 2.2下使用环回接口,最大可收发IP数据报长度为65535字节。
从Solaris 2.2到AIX 3.2.2,发送的最大IP数据报长度可以是65535字节。很显然,这个限制与源端和目的端的实现有关。
主机必须能够接收最短为576字节的IP数据报。在许多UDP应用程序的设计中,其应用程序数据被限制成512字节或更小,因此比这个限制值小。

由于IP能够发送或接收特定长度的数据报并不意味着接收应用程序可以读取该长度的数据。因此,UDP编程接口允许应用程序指定每次返回的最大字节数。如果接收到的数据报长度大于应用程序所能处理的长度,那么会发生什么情况呢?不幸的是,该问题的答案取决于编程接口和实现。
典型的Berkeley版socket API对数据报进行截断,并丢弃任何多余的数据。应用程序何时能够知道,则与版本有关(4.3BSD Reno及其后的版本可以通知应用程序数据报被截断)。
SVR4 下的socket API(包括Solaris 2.x) 并不截断数据报。超出部分数据在后面的读取中返回。它也不通知应用程序从单个UDP数据报中多次进行读取操作。TLI API不丢弃数据。相反,它返回一个标志表明可以获得更多的数据,而应用程序后面的读操作将返回数据报的其余部分。在讨论TCP时,我们发现它为应用程序提供连续的字节流,而没有任何信息边界。TCP以应用程序读操作时所要求的长度来传送数据,因此,在这个接口下,不会发生数据丢失。

对于TCP协议来说,整个包的最大长度是由最大传输大小(MSS,Maxitum Segment Size)决定,MSS就是TCP数据包每次能够传 输的最大数据分段。为了达到最佳的传输效能TCP协议在建立连接的时候通常要协商双方的MSS值,这个值TCP协议在实现的时候往往用MTU值代替(需要减去IP数据包包头的大小20Bytes和TCP数据段的包头20Bytes)所以往往MSS为1460。通讯双方会根据双方提供的MSS值得最小值 ,确定为这次连接的最大MSS值。

IP层:
对于IP协议来说,IP包的大小由MTU决定(IP数据包长度就是MTU-28(包头长度)。 MTU值越大,封包就越大,理论上可增加传送速率,但 MTU值又不能设得太大,因为封包太大,传送时出现错误的机会大增。

UDP 包的大小就应该是 1500 – IP头(20) – UDP头(8) = 1472(BYTES)
TCP 包的大小就应该是 1500 – IP头(20) – TCP头(20) = 1460 (BYTES)

当我们发送的UDP数据大于1472的时候会怎样呢?这也就是说IP数据报大于1500字节,大于 MTU.这个时候发送方IP层就需要分片(fragmentation).把数据报分成若干片,使每一片都小于MTU.而接收方IP层则需要进行数据报的重组.这样就会多做许多事情,而更严重的是,由于UDP的特性,当某一片数据传送中丢失时,接收方便无法重组数据报.将导致丢弃整个UDP数据报。
因此,在普通的局域网环境下,我建议将UDP的数据控制在1472字节以下为好.
进行Internet编程时则不同,因为Internet上的路由器可能会将MTU设为不同的值.如果我们假定MTU为1500来发送数据的,而途经的某个网络的MTU值小于1500字节,那么系统将会使用一系列的机制来调整MTU值,使数据报能够顺利到达目的地,这样就会做许多不必要的操作.

一般默认的设置,PPPoE连接的最高MTU值是1492, 而以太网 (Ethernet)的最高MTU值则是1500,而在Internet上,默认的MTU大小是576字节。

鉴于 Internet上的标准MTU值为576字节,所以我建议在进行Internet的UDP编程时.最好将UDP的数据长度控件在548字节 (576-8-20)以内.


许多服务器将最大的UDP数据包限制为512字节(如dns)

IPv4 最小重组缓冲区大小是576,IPv6在1500处。从这里减去标头大小。请参阅W. Richard Stevens的UNIX网络编程

576字节是最小的缓冲区大小,即每个实现必须能够重组至少那个大小的分组。有关详细信息,请参阅IETF RFC 1122

安全UDP的有效载荷最大是508字节。这是一个数据包大小为576,减去最多60个字节的IP标头和8个字节的UDP标头。任何这个规模或更小的UDP有效载荷都保证可以通过IP交付(尽管不能保证完整的交付)。由于其他原因,在路由的过程中可能会丢失。除了仅IPv6路由,最大有效载荷为1,212字节。正如其他人所提到的,在某些情况下可以添加额外的协议头。取而代之的是300-400字节的存储空间。

任何UDP数据包都可能被分割。这并不重要,因为丢失一个数据包与丢失一个未分组的数据包具有相同的效果:使用UDP,整个分组被丢弃的这种种情况是可能发生的。

一个典型 IPv4报头为20个字节,和UDP头部为8个字节。但是又包含IP选项,这可以将IP报头的大小增加到60个字节。另外,有时中间节点需要将数据报封装在另一个协议中,如IPsec(用于VPN等),以便将数据包路由到目的地。因此,如果你不知道MTU特定网络路径的话,最好为其他标题信息留下合理的存储空间,可能这些信息并不是你预期的。通常认为UDP的有效载荷是512字节,即使这样处理也不能为最大尺寸的IP标头留下足够的存储空间。


抓包实测 – UDP/TCP数据包分析

经测试,局域网环境下,UDP包大小为1024*8,速度达到2M/s,丢包情况理想.
外网环境下,UDP包大小为548,速度理想,丢包情况理想.

本文旨在分析使用抓包工具抓取到的数据包。

(一)抓包工具

tcpdump:linux下的抓包利器

wireshark:带GUI的抓包工具,其前身是大名鼎鼎的Ethereal

(二)抓包

这里只简述tcpdump的一般用法,详细资料可参考tcpdump使用手册。

wireshark带有GUI,操作比较简单,暂不赘述。

tcpdump -i eth1 tcp -Xnlps0 port 16815 src host 192.168.0.0 and dst net 192.168.0.1
tcpdump -i eth1 -Xnlps0 dst net 172.23.9.155 and port 37861
tcpdump -i eth1 -Xnlps0 dst net 172.23.9.155 and port 37861 -w yourfile

PS:可以使用wireshark分析tcpdump抓取的数据包

tcpdump -w output.cap -s0

wireshark可以在图形界面下分析应用层按照TCP/IP四层结构显显示数据包,
第一行是数据链路层的信息,
第二行是网络层信息(IP协议),
第三行是传输层信息(TCP协议),
第四行是应用层信息(HTTP协议),
可以展开每一行用来观察具体的内容

(三)TCP/UDP数据包结构

抓包分析,装载udp的ip包和装载tcp的ip包,查明ip包首部都没有添加可选项。

PS:后面的数据分析都是带IP头的数据包。

(四)UDP数据包分析

0x0000:  4500 0054 9a08 4000 4011 b88d ac17 8639  [email protected]@……9
0x0010:  ac17 099b e317 93e5 0040 e854 0000 0065  ………@.T…e
0x0020:  012d d668 0000 0000 0000 0000 0000 0038  .-.h………..8
0x0030:  3030 3030 3030 3030 3030 3030 3030 3030  0000000000000000
0x0040:  0000 0001 0000 0000 0000 0000 0000 0000  …………….
0x0050:  0000 0000

4500        [4: ipv4], [5: header length, *4 ==> 20], [00: Type of Service(TOS)]
0054        [total length: 0x54(84), ip header(20) + udp header(8) + packlen(56) -> 84]
9a08        id
4000        3bits(ip flags), 40 -> do not flag, 5bits: fragment offset
4011        [ttl: 40], [protocol: 0x11(17) ==> udp]
b88d        checksum
ac17 8639   source ip: 172.23.134.57

ac17 099b   dest ip: 172.23.9.155
e317        sourc port: 58135 (ntohs(0xe317)) [exchange]
93e5        dest port: 37861
0040        length: 64
e854        checksum

0000 0065…  data

 

(五)TCP数据包分析

0x0000:  4500 0073 cdc5 4000 4006 6285 ca6e 4099  [email protected]@[email protected]
0x0010:  7474 8abe 1f40 070a 6d88 acdd 23d7 a448  tt…@..m…#..H
0x0020:  5018 16d0 0aa0 0000 0100 8000 0000 0047  P…………..G
0x0030:  3004 8000 0016 8117 04d7 cd00 000b 0006  0……………
0x0040:  4500 1a4d 6bd0 180a 909a bc08 883d edea  E..Mk……..=..
0x0050:  091f                                     ..

4500        [4: ipv4] [5: ip header length, 4*5 -> 20] [00 TOS]
0073        [total length: 0x73(115), ip header(20) + tcp header(20) + packlen(75) -> 115]
cdc5        id(ignore it)
4000        3bits(ip flags), 40 -> do not flag, 5bits: fragment offset
4006        [40 ttl] [06 protocol, 0x06 -> tcp]
6285        checksum
ca6e 4099   source ip: 202.110.64.153

7474 8abe   dest ip: 116.116.138.190
1f40        sourc port: 8000 (ntohs(0x401f)) [exchange]
070a        dest port: 1802
6d88 acdd   32 bits sequence number(ignore)
23d7 a448   32 bits ack(ignore)

5018        [5: tcp header length 5 * 4 -> 20] [018: 0000 00/01 1000: reserved 6bit -> ACK+PUSH] (URG|ACK|PSH|RST|SYN|FIN)
16d0        16bit window size: 5840
0aa0        16bit tcp checksum(ignore)
0000        16bit urgent pointer
———————

抓包工具:科来网络分析系统

https://blog.csdn.net/cybertan/article/details/5961049

参考:

https://blog.csdn.net/wirror800/article/details/6977421

https://blog.csdn.net/buptzwp/article/details/5055487

网络原理-计算机网络详解-网线传递数字信号的原理

家用的网线:传递的数字信号,原理是:

(1)和电线传输电的原理一样,只不过网线上传输的就是脉冲电信号,而且遵守一定的电器规则。
(2)计算机上的数据都是用0和1来保存的,所以在网线上传输时就要用一个电压表示数据0,用另一个电压表示数据1。
(3)网线上传输的是数字信号。
(4)网线在传输数据就是传输电信号,就会有电流通过,那么就会产生电磁场,几根线之间的电磁场就会互相干扰,会影响电压,使得数据失真,所以把绞在一起就可以有效的抵消掉这种线之间的互相电磁干扰。

总结来说:网线就是传递的脉冲电信号,在一个脉冲中,即有电压变化,又有电流变化。
网线传输信号是数字信号,方波,相当脆弱,容易受到周边磁场和自身的干挠。所以双绞的原理就是为了尽可能的消除其干挠。
我们日常使用最多的网线就是双绞线,但网线不能过长,电脑能识别的语言就只有0和1,网络得传输信号就是0和1。这些信号通过网线的时候变成了电流,而网线的电流强度是-15v和+15v之间,电流通过网线传输的时候会有电阻。所以,根据高压输电原理,线路越长,就要用越大的电压等级来输电。如果网线过长,但是这么低的电压,就会导致信号减弱,直至丢失。因此网线不宜过长,一般来说,网线超过一百米,另一头就接收不到信号了。

rj45网线中,单方向传输信号都是一对导线,里面用的是差分信号,传递给对方的是电压变化 信号。【双绞线 可以 屏蔽 外界的 电磁干扰,抗干扰强】

如果差分信号电路中的源和接收器阻抗相等,则外部电磁干扰往往会同样影响两个导体。由于接收电路仅检测导线之间的差异,因此与具有未配对参考(接地)的一个导体相比,该技术抵抗电磁噪声。该技术适用于模拟信号,如平衡音频和数字信号,如RS-422,RS-485,双绞线以太网,PCI Express,DisplayPort,HDMI和USB。【来自维基百科】

数字电路:从 单端信号 发展到 差分信号

单端信号与同轴电缆一起使用,其中一根导线完全屏蔽另一根导线与环境。所有屏幕(或屏蔽)都组合成一块材料,形成一个共同的地面。差分信号与平衡的导体对一起使用。对于短电缆和低频,这两种方法是等效的,因此具有公共接地的廉价单端电路可以与廉价电缆一起使用。

单端信号
早期的数字总线大部分使用单端信号做信号传输,如TTL/CMOS信号都是单端信号。所谓单端信号,是指用一根信号线的高低电平的变化来进行0、1信息的传输,这个电平的高低变化是相对于其公共的参考地平面的。单端信号由于结构简单,可以用简单的晶体管电路实现,而且集成度高、功耗低,因此在数字电路中得到最广泛的应用。

大白话:单端信号 用一根线 接地,另一根 传递 电压 高低变化,当然也是 单方向 传输啦。

======================================================

差分传输是一种信号传输的技术,区别于传统的一根信号线一根地线的做法,差分传输在这两根线上都传输信号,这两个信号的振幅相同,相位相反。在这两根线上的传输的信号就是差分信号。信号接收端比较这两个电压的差值来判断发送端发送的逻辑状态。在电路板上,差分走线必须是等长、等宽、紧密靠近、且在同一层面的两根线。

差分信号是用一个数值来表示两个物理量之间的差异。差分信号又称差模信号,是相对共模信号而言的。


网线传输原理

一般情况下,网络从上至下分为五层:应用层、传输层、网络层、数据链路层、物理层。每一层都有各自需要遵守的规则,称之为“协议”。TCP/IP协议就是一组最常用的网络协议。
网线在网络中属于物理层,计算机中所需要传输的数据根据这些协议被分解成一个一个数据包(其中包括本地机和目的机的地址)后,按照一定的原则最后通过网线传输给目的机。通俗讲,和我们去寄信的道理一样,先写好信的内容(计算机上的数据)、装信封然后在封面上写地址(打包成数据包,里面包含本地机和目的机的地址)、寄出(传输),那么网线就相当于你的地址和你要寄到的地址之间的路。
(1)如上所述,和电线传输电的原理一样,只不过网线上传输的就是脉冲电信号,而且遵守一定的电气规则。
(2)计算机上的数据都是用0和1来保存的,所以在网线上传输时就要用一个电压表示数据0,用另一个电压表示数据1。
(3)网线上传输的是数字信号
(4)网线在传输数据就是传输电信号,就会有电流通过,那么就会产生电磁场,几根线之间的电磁场就会互相干扰,会影响电压,使得数据失真,所以把绞在一起就可以有效的抵消掉这种线之间的互相电磁干扰。
网线传输信号是数字信号,方波,相当脆弱,容易受到周边磁场和自身的干挠。所以双绞的原理就是为了尽可能的消除其干挠。
明白了网线所接的水晶头:rj45接口原理就自然明白了网线的原理:
RJ-45各脚功能(10BaseT/100BaseTX):
1、传输数据正极   Tx+
2、传输数据负极   Tx-
3、接收数据正极   Rx+
4、备用(当1236出现故障时,自动切入使用状态)
5、备用(当1236出现故障时,自动切入使用状态)
6、接收数据负极   Rx-
7、备用(当1236出现故障时,自动切入使用状态)
8、备用(当1236出现故障时,自动切入使用状态)
网线中传输的是数字信号,网卡工作在物理层,是将数据根据OSI的七层协议,从要传输的数据一级一级的转换成帧数据,用电信号的方式传输出去,接收方依同样的原理,转换成对方的原始数据。
RJ-45的接头实现了网卡和网线的连接。它里面有8个铜片可以和网线中的4对双绞(8根)线对应连接。其中100M的网络中1、2是传送数据的,3、6是接收数据的。1、2之间是一对差分信号,也就是说它们的波形一样,但是相位相差180度,同一时刻的电压幅度互为正负。这样的信号可以传递的更远,抗干扰能力强。同样的,3、6也一样是差分信号。
网线中的8根线,每两根扭在一起成为一对。我们制作网线的时候,一定要注意要让1、2在其中的一对,3、6在一对。否则长距离情况下使用这根网线的时候会导致无法连接或连接很不稳定。
首先说一下差分方式传输。所谓差分方式传输,就是发送端在两条信号线上传输幅值相等相位相反的电信号,接收端对接受的两条线信号作减法运算,这样获得幅值翻倍的信号。其抗干扰的原理是:假如两条信号线都受到了同样(同相、等幅)的干扰信号,由于接受端对接受的两条线的信号作减法运算,因此干扰信号被 基本抵消,那么怎样才能保证两条信号线受到的干扰信号尽量是同相、等幅的呢?办法之一那就要将两根线扭在一起,按照电磁学的原理分析出:可以近似地认为两条信号线受到的干扰信号是同相、等幅的。 两条线交在一起后,既会抵抗外界的干扰也会防止自己去干扰别人。一般常用的就是双绞线。
大多数局域网使用非屏蔽双绞线(UTP—Unshielded Twisted Pair)作为布线的传输介质来组网,网线由一定距离长的双绞线与RJ45头组成。双绞线由8根不同颜色的线分成4对绞合在一起,成队扭绞的作用是尽可能减少电磁辐射与外部电磁干扰的影响,双绞线可按其是否外加金属网丝套的屏蔽层而区分为屏蔽双绞线(STP)和非屏蔽双绞线(UTP)。在EIA/TIA-568A标准中,将双绞线按电气特性区分有:三类、四类、五类线。网络中最常用的是三类线和五类线,超五类,目前已有六类以上线。第三类双绞线在LAN中常用作为10Mbps以太网的数据与话音传输,符合IEEE802.3 10Base-T的标准。第五类双绞线目前占有最大的LAN市场,最高速率可达100Mbps,符合IEEE802.3 100Base-T的标准。做好的网线要将RJ45水晶头接入网卡或HUB等网络设备的RJ45插座内。相应地RJ45插头座也区分为三类或五类电气特性。RJ45水晶头由金属片和塑料构成,特别需要注意的是引脚序号,当金属片面对我们的时候从左至右引脚序号是1-8, 这序号做网络联线时非常重要,不能搞错。双绞线的最大传输距离为100米。 EIA/TIA的布线标准中规定了两种双绞线的线序568B与568A。
标准568B:橙白–1,橙–2,绿白–3,蓝–4,蓝白–5,绿–6,棕白–7,棕–8
标准568A:绿白–1,绿–2,橙白–3,蓝–4,蓝白–5,橙–6,棕白–7,棕–8
568A和568B两者有何区别呢?后者是前者的升级和完善,但是后者还处于草案阶段,包含永久链路的定义和六类标准。另外在综合布线的施工中,有着568A和568B两种不同的打线方式,两种方式对性能没有影响,但是必须强调的是在一个工程中只能使用一种打线方式。
至于5类和超5类的不同主要是应用的不同。5类系统在使用过程中只是使用其中的两对线缆,采用的是半双工,而超5类为了满足千兆以太网的应用,采用四对全双工传输。因而远端串扰(FEXT),回波损耗(RL)、综合近端串扰(PSNEXT)、综合ACR和传输延迟也成为必须考虑的参数。所以超5类比5类有着更高的性能要求。6类和5类实质的区别在于它们的带宽不同,5类只有100MHz,六类是250MHz。它们支持的应用也因为性能的不同而不同,6类支持更高级别的应用。在性能上6类也比5类有更高的要求,为了提高性能,在结构上6类比5类也要复杂一些RJ45接头的8个接脚的识别方法是,铜接点朝自己,头朝右,从上往下数,分别是1、2、3、4、5、6、7、8。
在整个网络布线中应用一种布线方式,但两端都有RJ-45 的网络联线无论是采用568A,还是568B, 在网络中都是通用的。规定双工方式下本地的1、2两脚为信号发送端,3、6两脚为信号接收端,所以讲,这两对信号必须分别使用一对双绞线进行信号传输。在做线时要特别注意。现在100M网一般使用568B方式,1、2两脚使用橙色的那对线,其中白橙线接1脚;3、6两脚使用绿色的那对线,其中白绿线接3脚,绿线接6脚,剩下的两对线在10M、100M快速以太网中一般不用,通常将两个接头的4、5和7、8两接头分别使用 一对双绞线直连,4、5用蓝色的那对线,4为蓝色,5为白蓝色;7、8用棕色的那对线,7为白棕色、8为棕色。如果网线两头都按一种方式这么做的话就叫做直连缆方式或直通线方式。
如果网线的两头不按一种方式,一头是568B,另一头是568A,那么这种做法叫交*缆,其实就是只须将其中一个 头在568B的基础上1、2和3、6对调一下就行。不同的做法用在不同的环境,后面会讨论。
很多人以为做直连缆时将线排成,这是错误的。这既不是568A也不是568B。这种做法3、6信号线未绞在一起,失去了双绞线的屏蔽作用。虽然在传输距离近时能正常使用不容易被发现,当传输距离远时会出现丢包,或者导致局域网速度慢,很多人会怀疑网卡质量和网线质量,往往不会想到是线做的有问题。
当网线作为局域网线路时,电压不超过3伏
作为电话线路时,电话在待机状态(即没拿起来时)供电电压为-48V(反向电位) 当电话被打通需要震铃时,供电电压为+48V(正向电位)并且叠加24V 25HZ交流,使其成为72V交流25HZ震荡信号。这样就会震铃了。 当拿起电话后(无论是对方打来还是你自己拿起)电压从-48V下降并转换为+8—+18V(这个由你线路距离局端设备远近而不同) 电话是以恒流方式供电。也就是,电流一定,功率越大,电压越高。并且除了震铃之外,其他的全部为直流送电,包括脉冲直流 并且,如果是之后新装的线路中,大多地区已经使用数字模拟混合接入,即若你的电话为06年之后购买并符合标准的,则为数字信号,用载波模式装载到线路中传输,若为之前的或者局端设备还没有更新,那么则是模拟信号,用电流高低震荡的方式传送。
作为电口出来的网线时,网线供电器的输出电压一般是24V或者48V,INTEL的设备就是24V,CISCO和神脑的设备就是48V,这样经过100米的网线传输后,电压还是足够的,而这些网络设备内部还有一个转换电路,将这些可能高于要求的电压降到正常范围内。
数字信号从Internet上下载下来,通过ISP接入你所在区域的交换机,通过D/A变换变成模拟信号,经过4线至2线的变换后,传到你的调制解调器,再经过一次A/D变换,还原成计算机可接受的数字信号。


无线网快还是插网线快?

同一个路由器下,绝大多数情况下,网线比无线网快。

不敢说绝了,因为上网情况不太,实际上网速度也有略有影响。

正常来说,插网线的网络损耗比较少,在局域网中常见的网线主要有双绞线、同轴电缆、光缆三种。 双绞线,是由许多对线组成的数据传输线。它的特点就是价格便宜,所以被广泛应用,如我们常见的电话线等。它是用来和RJ45水晶头相连的。

我们日常使用最多的网线就是双绞线,但网线不能过长,电脑能识别的语言就只有0和1,网络得传输信号就是0和1。这些信号通过网线的时候变成了电流,而网线的电流强度是-15v和+15v之间,电流通过网线传输的时候会有电阻。所以,根据高压输电原理,线路越长,就要用越大的电压等级来输电。如果网线过长,但是这么低的电压,就会导致信号减弱,直至丢失。因此网线不宜过长,一般来说,网线超过一百米,另一头就接收不到信号了。

而我们正常使用网线的一般只有几米,损耗是非常少的。

无线网络损耗比较大的原因比较多,如建筑物对网络的损耗,特别是建筑物中的承重墙对网络损耗会比较大。由于wifi信号有特定的信道,这些信道就如同告诉公路,如果附件多个路由器发射出来的wifi都在一个信道传输,也会导致网络变慢。

在家中使用PC用网线连接路由器比wifi连接网速还是要更好的。

其实路由器端是没有太大问题的,虽然标称300m的2.4gWIFI有大半虚标,但实际值还是比有线的100m快的。但是问题就在于你的笔记本电脑,手机和便宜的无线网卡速率都是54m!

这就产生瓶颈制约,路由器标称给你6碗饭,实际给你3碗饭,但你只吃得下1碗!

现在的电脑配置也有问题,机械硬盘标称和测速都显示130m/s以上,但实际上使用起来持续速度只有40m/s左右,因为机械盘早期写入的是缓存,缓存再写入碟片,但测速软件测的是写入缓存的速度而非写入盘片的速度。测速450m/s的ssd真实持续写入速度其实也就95m/s。

40m/s换算为速率就是480mbps,所以,你的电脑根本上来说就只能用480m的网速,什么千兆网卡都是噱头,因为根本没这能力跑!ssd会好一些,但是也只能勉强跑满千兆!

千兆有线的设备成本比较低,而你如果想用千兆WIFI,光路由器和接收器的投资就不低于2500元,而且还要专用,不能通用。

总之,这是这个时代的科技局限,你手机无线接收模块就只54mbps,速度上限就7m/s,5g的会好点,但也只能到15m/s左右的上限。你用再好的路由器都没用!

包括现在的小米用了黑科技双WIFI,但也只能增加WIFI信号强度而不能增加速度。

总结:现在普遍使用百兆有线的情况下,有线是要比无线快的,想要无线比有线快,要等高标准的WIFI接收模块普及了才行。

首先有两个概念。

我们常说的网速:“XX兆光纤”,对应到一个专业词汇叫“网络带宽”。指的是单位时间的传输效率,一般运营商给的这个值是理论最大值。实际情况往往到不了这个大小。一个比较好的类比是,带宽越大,就好像一个高速公路修得越宽,车道越多。
第二个生活化的词汇是“网好卡”,对应到专业词汇叫“网络延迟”,延迟有很多部分组成,也受很多因素影响。但最终用户感受到的是一个网络请求从开始到收到结果的时间间隔。可以类比为高速公路上的车跑的快慢。
所以上面我们可以看出,网络“卡不卡”是有两个指标衡量的,在不同的使用场景下时有不同的判断依据的。

下面举例两个场景。

用手机或者电脑打游戏的时候,往往游戏需要发生的网络请求很频繁但是数据量并不大。这个时候我们需要网络延迟很低,但是并不需要有很大的网络带宽。所以我们经常能看到,隔壁老王家10兆的网络比你家100兆的网络打游戏更加顺畅。类比到高速公路上,就是相当于有很多赛车一辆接一辆在两个地方往返,这个时候路面是不是很宽其实大家不太在乎,在乎的是“路好不好走”,也就是延迟是不是很低。
在线观看视频或者下载资料的时候,电脑会从网络上不断的下载信息,放到本地,供我们观看。这些信息相对是非常大的,这时候我们就需要很宽的公路去运送这些资源到本地来,路面稍微难走一点也没有关系。这个场景下我们需求的是大的带宽,对延时没有太高的要求。
说完了啥叫网络卡,以及不同场景下的不同需求,我们来看一看有线连接和无线连接的区别。(这只讨论家用路由器和日常使用设备之间的连接形式)。

顾名思义有线连接就是信息由路由器到主机之间用光缆连接以传输信息,信息传输过程是先将电信号转化为光信号在光缆中传输,然后另一端接收到结果后再由光信号转换为电信号。完成传输。在光缆内传输的好处是,受到外界干扰很小,而且本身带宽也足够大(现在市面上光缆的传输带宽都是远大于我们家用网络带宽的)。
而无线连接则是,路由器和主机之间,将电信号通过调制解调器转换,以电磁波为载体在端与端之间传输。优势在于方便。但是劣势也很明显,例如电磁波比较容易受到干扰,传输带宽和发射功率有关,以及多个无线网信道之间相互干扰等等
所以从理论上看,相应其他条件下,有线连接会比无线连接在网络带宽和网络延时上都更具有优势一些。

至于其他答案中提到的2.4G和5G标准相关的内容,其实都是这个标准下用了全新不易冲突的电磁波频段以及新的硬件标准使得相同功率下传输效率更高。但是现阶段而言,不太可能突破有线连接的速度。

再顺便提及一下某些朋友可能的疑虑,电脑接有线,手机用无线,体验上手机比电脑更加流畅。这个问题其实很简单,做对比要控制好变量,很可能体验上的差别是由其他东西导致的。比如运营商在晚高峰的时候承诺的带宽达不到,或者晚高峰网络拥塞整体延时都增加了等等。

你们见过数据中心用无线传业务数据吗?!

1.无线工作方式为半双工,类似于以前那种很老的hub(冲突检测,载波侦听,就是我在用的时候你就得等着我把数据传完你再传)。

2.无线的吞吐看起来参数比千兆有线还高(1200Mbps甚至5300Mbps),但他的工作方式决定了它在多用户的环境下性能损失非常大,特别是多用户大吞吐的时候,抖动增大和速率下降都会非常利害,信号也容易受到干扰还不安全。

3.现在高端一点的无线路由器在硬件层面有mimo数据流的多入多出,链路聚合,专用无线处理芯片等技术,但其实性能提升也有限,原因还是看第一点他的工作原理决定的。软件层面会有一些专业的商业公司出的专用操作系统比如aruba,Cisco,huawei等,但也只是在稳定性,安全性和部署维护上进行了优化。

4.有线的路由器或者交换机会有专门的处理芯片来处理三层的路由数据和二层的交换数据,一般都能达到线速转发。比如48口的交换机背板宽带宽228Gbps,实际上只要用到96Gbps就足够让这48台终端同时上下行并发吞吐数据了,而且延时抖动和速率下降并不明显,如果是无线分分钟死给你看。但是呢即使是dlink tplink fast 腾达之流,瞎标参数,千兆有线也比大牌的千兆无线快和稳定,但不用说那种专业厂商的设备。

个人经验,高端点的ac无线路由器单纯的作为接入点30人左右的接入会有比较好的用户体验,尽管他可能支持128或者更高的接入,但能连接和可以用可是二码事。一分钱一分货,那种几十块的就不用说了,家庭3到5个人,要求不高,也能用。

所以,至少一段时间来看无线都只是作为接入层的扩展设备而存在,因为他不用布线方便啊

参考链接:

https://www.bilibili.com/read/cv1166002/

https://www.diangon.com/thread-17307-1-1.html

浏览器调试-Chrome调试JavaScript入门

平常在开发过程中,经常会接触到前端页面。那么对于js的调试那可是家常便饭,不必多说。最近一直在用火狐的Firebug,但是不知道怎么的不好使了。网上找找说法,都说重新安装狐火浏览器就可以了,但是我安装了好多遍,也没好使,后来听说Firebug停止更新了。没办法既然不给用,那我换浏览器不就可以了嘛!一开始想到就是谷歌,谷歌浏览器是常用来调试JS代码的工具,本文主要介绍如何利用谷歌浏览器来调试JS代码,协助我们进行开发工作,加快开发效率。

1、首先,打开谷歌浏览器,然后打开调试功能栏,按快捷键F12或者ctrl+shift+j,就可以打开谷歌浏览器的开发者工具。打开后页面如下所示。

2、下面主要介绍一下开发者工具中常用的几个基础常用功能。左上角第二个选项,是用来切换手机页面的。如果我们访问的网址是手机端wap页面,则点击此按钮,就可以模拟手机进行访问了。

3、Network是网络工具,可以查看请求数据的状态,类型,大小,时间等,如下图。Network是在调试中常用的工具,可以查看发送的请求是否正确,返回的数据是否正常等。

4、Sources可以用来查看页面的源文件,包括JS文件和Html文件。找到想要调试的JS代码,在代码前单击,即可设置断点。当运行JS代码时,会自动进入到断点执行。同Java调试类似,JS调试也可以单步运行、进入函数体内调试、直接运行到下一断点等。

5、如上图所示,右上角4个断点,分别是直接运行到下一断点、单步运行、进入函数体内运行、返回函数执行结果。对应的快捷键分别是F8、F10、F11和shift+F11。在调试时,把鼠标放在某个变量上,就可以查看该变量的运行值。

 

 

人要耐得住寂寞,才能守得住繁华。人生最痛苦的就是拿不起放不下,不属于自己的快乐,及时放手也许是一种解脱,生活中没有谁对谁错,只有适不适合。当发现很多已经改变,更要面对的是事实。

来自:https://www.cnblogs.com/yuanchaoyong/p/6172034.html

服务器开发-概述

想做一个简单的服务器,用来更好的了解web交互模式。


http1.0 简单服务器 :三个文件

package com.httpserver;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

import javax.swing.JTextArea;
import javax.swing.JTextField;


public class HttpResponse extends Thread {
	Socket socket;
	JTextArea ta;
	PrintStream pout;
	boolean isHttp1 = false;
	String path = null;
	HttpResponse(Socket socket, JTextArea ta,JTextField path)
	{
		this.socket = socket;
		this.ta = ta;
		this.path = path.getText();
	}
	
	public void run()
	{
		try {
		
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			pout = new PrintStream(socket.getOutputStream());
			String requestLine = br.readLine();
			//String requestCmds = ""+requestLine;
			if(requestLine==null){
				error(400,"Empty Request");
			}
			else{
				ta.append("Http请求,来自:["+socket.getInetAddress()+":"+socket.getPort()+"]   "+requestLine+"\n");
			}
			if(requestLine.toLowerCase().indexOf("http/1.")!=-1){
				isHttp1 = true;
			}
			String[] request = requestLine.split(" ");
			if(request.length<2)
			{
				error(400,"Bad Request");
			}
			String str1 = request[0];
			if(str1.equals("GET")){
				serveFile(request[1]);
			}
			else{
				error(400, "Bad Request");
				ta.append("Bad Request");
			}
			
			socket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			return;
		}
		
	}
	
	
	private void error(int erorcd, String erortx) {
		erortx = "<html><h1>" + erortx + "</h1></html>";
		if (isHttp1) {
			pout.println("HTTP/1.0 " + erorcd + " " + erortx);
			pout.println("Content-type: text/html");
			pout.println("Content-length: " + erortx.length() + "\n");
		}
		pout.println(erortx);
	}
	
	private void serveFile(String requestPath)  {
		if (requestPath.equals("/")){
			/**
			 * 取首页文件,首页文件可以为index.html或index.htm
			 */
			requestPath = "/index.html";
			if(path==null){
				path=new File("").getAbsolutePath();
			}
			if(!new File(path+requestPath).exists()){
				requestPath="/index.htm";
			}			
		}				
		try {
			sendFileData(requestPath);
			ta.append("文件传输成功 !       "+requestPath+"\n");
		} catch (Exception e) {
			error(404, "");
			ta.append("请求文件不存在\n");
		}		
	}
	
	private void sendFileData(String requestPath) throws IOException,FileNotFoundException {
		InputStream inputstream = new FileInputStream(path+requestPath);
		if (inputstream == null)
			throw new FileNotFoundException(requestPath);		
		if (isHttp1) {
			pout.println("HTTP/1.0 200 Document follows");
			pout.println("Content-length: " + inputstream.available());
			
			if (requestPath.endsWith(".gif"))
				pout.println("Content-type: image/gif");
			else if (requestPath.endsWith(".jpg"))
				pout.println("Content-type: image/jpeg");
			else if (requestPath.endsWith(".png") || requestPath.endsWith(".htm"))
				pout.println("Content-Type: text/png");
			
			else if (requestPath.endsWith(".css") || requestPath.endsWith(".htm"))
				pout.println("Content-Type: text/css");
			else if (requestPath.endsWith(".js") || requestPath.endsWith(".htm"))
				pout.println("Content-Type: text/javascript");

			else if (requestPath.endsWith(".html") || requestPath.endsWith(".htm"))
				pout.println("Content-Type: text/html");

			else
				pout.println("Content-Type: application/octet-stream");
			
			pout.println("Connection: Keep-Alive");//println 表示写完自带换行
			/*****下面这个换行回车,必须要有 这个是报头 格式******/
			pout.println();
			/***** 但是这个 只需要一个换行回车就行了 **/
			//pout.println();

           
			
		}
		/*缓冲区设为8K*/
		byte[] is = new byte[8*1024];
		/*实际测试 缓冲区 太小了,请求一张 大于 8K 的图片就 无法传输了,好像不是这个问题*/
		//byte[] is = new byte[300*1024];

		
		int length=0;
		while((length=inputstream.read(is))!=-1){
			pout.write(is, 0, length);
		}
		inputstream.close();
		pout.flush();
	}

}
package com.httpserver;

import java.net.*;

import javax.swing.*;

public final class ServerThread extends Thread {
	int port;
	JTextArea display;
	JTextField status;
	JTextField direc;
	//JTextField ipAdd;
	ServerSocket listener = null;
	ServerThread (int port, JTextArea display, JTextField status,JTextField direc,JTextField ipAdd) throws Exception
	{
		this.port = port;
		this.display = display;
		this.status = status;
		this.direc = direc;
		byte[] ip = new byte[4];
		String ipp = ipAdd.getText();
		//System.out.println(ipp);
		String[] ip1 = ipp.split("\\.");
		for(int i = 0;i<ip1.length;i++){
			try{
				ip[i] = (byte) Integer.parseInt(ip1[i]);
			}
			catch(Exception e){
				ip[i] = -1;
			}
			//System.out.println(ip1[i]);
		}
		//System.out.println(ip[0]+" "+ip[1]+" "+ip[2]+" "+ip[3]);
		//this.ipAdd = ipAdd;
		try{
			listener = new ServerSocket(port,20, InetAddress.getByAddress(ip));
		}
		catch(Exception e){
			
			listener = new ServerSocket(port,20);
			display.append("无效的IP地址,已使用默认地址:"+InetAddress.getLocalHost().getHostAddress()+"\n");
			ipAdd.setText(InetAddress.getLocalHost().getHostAddress());
		}
		display.append("服务器已开启,端口:"+port+"\n");
		status.setText("服务器已开启。 "+ipAdd.getText()+":"+port+"  "+direc.getText());
	}
	
	public void run()
	{
		
		
		while(true)
		{
			try{
				Socket socket = listener.accept();
				/*for(String s = new BufferedReader(new InputStreamReader(socket.getInputStream())).readLine();s!="\n";
						s = new BufferedReader(new InputStreamReader(socket.getInputStream())).readLine()){
					display.append(new BufferedReader(new InputStreamReader(socket.getInputStream())).readLine());
				}
				*/
				/*BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				for(String s = br.readLine();s!=null;s = br.readLine()){
					display.append(s+"\n");
				}*/
				new HttpResponse(socket, display, direc).start();
			}
			catch(Exception e){
				display.append(e+"\n");
			}
		}
	}
	
}
package com.httpserver;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.synth.SynthStyle;

public class Surface implements ActionListener {

	JFrame jf = new JFrame("Web Server");
	JLabel iP = new JLabel("IP: ");
	JLabel port = new JLabel("Port: ");
	JTextField ipAdd = new JTextField(15);
	JTextField portNum = new JTextField(4);
	JButton start = new JButton("Start");
	JButton over = new JButton("Stop");
	JLabel direct = new JLabel("Main Directory: ");
	JTextField directory = new JTextField(24);
	JButton br = new JButton("...");
	// JLabel diary = new JLabel("Diary:");
	JTextArea ta = new JTextArea(10, 40);
	// JTextField outDirct = new JTextField(15);
	// JTextField outIp = new JTextField(8);
	JTextField outStatus = new JTextField(40);
	// JLabel status = new JLabel("Status:");
	ServerThread listener = null;
	boolean hasStarted = false;
	String ipp;

	public void init() {
		JPanel jp1 = new JPanel();
		jp1.add(iP);
		jp1.add(ipAdd);
		jp1.add(port);
		jp1.add(portNum);
		jp1.add(start);
		jp1.add(over);
		JPanel jp2 = new JPanel();
		jp2.add(direct);
		jp2.add(directory);
		jp2.add(br);
		// JPanel jp3 = new JPanel();
		// jp3.add(diary);
		// JScrollPane jsp = new JScrollPane();
		// jsp.add(ta);
		Border bb = BorderFactory.createEtchedBorder();
		Border tb1 = BorderFactory.createTitledBorder(bb, "Console");
		Border tb2 = BorderFactory.createTitledBorder(bb, "Diary");
		JScrollPane jsp = new JScrollPane(ta);
		JPanel jp4 = new JPanel();
		jp4.add(jsp);
		jp4.setBorder(tb2);
		ta.setLineWrap(true);
		ta.setEditable(false);
		start.addActionListener(this);
		over.addActionListener(this);
		br.addActionListener(this);
		Box jb1 = Box.createVerticalBox();
		jb1.add(jp1);
		jb1.add(jp2);
		jb1.setBorder(tb1);
		directory.setText("/Users/hello/Sites/testwebsites");
		// Box jb2 = Box.createVerticalBox();
		// jb2.add(jp3);
		// jb2.add(jp4);
		Box jb = Box.createVerticalBox();
		// jb.setBorder(bb);
		outStatus.setBackground(jf.getBackground());
		outStatus.setBorder(null);
		outStatus.setEditable(false);
		JPanel jp5 = new JPanel();
		jp5.setBorder(bb);
		// jp5.add(status);
		jp5.add(outStatus);
		outStatus.setText("服务器已停止");
		try {
			ipAdd.setText(InetAddress.getLocalHost().getHostAddress());
		} catch (Exception e) {
			ipAdd.setText("0.0.0.0");
		}
		jb.add(jb1);
		jb.add(jp4);
		jb.add(jp5);
		// jb.add(jp3);
		// jb.add(jp4);
		jf.add(jb);
		// jf.add(jp1);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setResizable(false);
		jf.pack();
		jf.setVisible(true);

	}

	public void startServer() {
		start.setEnabled(false);
		over.setEnabled(true);
		int port = 8080;
		try {
			port = Integer.parseInt(portNum.getText());
		} catch (Exception e) {
			ta.append("端口号异常,已使用8080端口。\n");
			portNum.setText("8080");
		}
		if (hasStarted && port == listener.port) {
			listener.resume();
			ta.append("服务器已开启,端口:" + listener.port + "\n");
			outStatus.setText("服务器已开启。" + ipp + ":" + port + "  " + directory.getText());
			// ipAdd.setText(InetAddress.getLocalHost().getHostAddress());
			return;
		}

		try {
			listener = new ServerThread(port, ta, outStatus, directory, ipAdd);
			ipp = ipAdd.getText();
		} catch (Exception e) {
			ta.append("端口已被其他程序占用,请重试。\n");
			listener = null;
			hasStarted = false;
		}
		if (listener == null) {
			start.setEnabled(true);
		} else {
			hasStarted = true;
			listener.start();
		}
	}

	public void exitServer() {
		ta.append("服务器关闭。\n");
		if (listener != null) {
			listener.stop();
		}
		System.exit(0);
	}

	public void stopServer() {
		start.setEnabled(true);
		over.setEnabled(false);
		listener.suspend();
		ta.append("服务器已停止。\n");
		outStatus.setText("服务器已停止。");
	}

	public void selectPath() {
		String str = "";
		String loc = "";
		JFileChooser chooser = new JFileChooser();
		chooser.setCurrentDirectory(new java.io.File("."));
		chooser.setDialogTitle("主目录");
		chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		chooser.setAcceptAllFileFilterUsed(false);
		if (chooser.showOpenDialog(jf) == JFileChooser.APPROVE_OPTION) {
			// str += chooser.getCurrentDirectory();
			str += chooser.getSelectedFile();
			loc = str.replaceAll("\\\\", "/"); //// Windows路径到JAVA路径的转换
		}
		directory.setText(loc);
	}

	public void actionPerformed(ActionEvent event) {
		String command = event.getActionCommand();
		if (command.equals("Start")) {
			startServer();
		}
		if (command.equals("Stop")) {
			stopServer();
		}
		if (command.equals("Exit")) {
			exitServer();
		}
		if (command.equals("...")) {
			selectPath();
		}
	}

	public static void main(String[] args) {
		Surface sf = new Surface();
		sf.init();
		// sf.outStatus.setText("服务器已开启:220.111.332.444:8000 sdafsagassasa");

		 String a = new String("源码下载站");
		 System.out.println("16制"+strTo16(a));

		char c = '8';
		System.out.printf("The value of char %c  %X,is %d.%n", c, (int)c,(int)c);
        //16进制 转成10进制。  java 内部编码是 utf-16 
		
		String str = String.valueOf(c);
		byte[] bys;
		try {
			bys = a.getBytes("UTF-8");
			for (int i = 0; i < bys.length; i++) {
				System.out.printf("%X ", bys[i]);
			}
            
			//因为是Unicode编码,所以编码前有字节序。
			//(byte & 0xFF) 这是一个字节相与,然后 << 8  代表数据 左移 8位 ,相当于 两字节大小 与后面的 或运算
			// 相当于 地位的字节 复制了 新添加的 字节
			//int unicode = (bys[2] & 0xFF) << 8 | (bys[3]& 0xFF);
			//System.out.printf("The unicode value of %c is %d.%n", c, unicode);

		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public static String strTo16(String s) {
		String str = "";

		System.out.println("字符串长度"+s.length());
		for (int i = 0; i < s.length(); i++) {
			int ch = (int) s.charAt(i);
			String s4 = Integer.toHexString(ch);
			str = str + s4;
		}
		return str;
	}

}

参考自:GitHub

另,Tomcat源码剖析电子书:

代码和UML图:https://github.com/Aresyi/HowTomcatWorks 
排版更好的百度电子书:https://yuedu.baidu.com/ebook/ac92f0d35122aaea998fcc22bcd126fff7055d60

网络编程资料:

自定义 服务器 css 设置成了 二进制类型 导致加载 不出来 样式,报文头和体 有且只有空一行 才能 被 浏览器 正确 解析。空两行 浏览器 加载不了 图片

http://localhost/~cool/beike/index.html

http://www.ietf.org/rfc/rfc1945.txt

 

http编码

https://blog.csdn.net/hongxingxiaonan/article/details/49963643

tcp连接详解:

https://blog.csdn.net/liuxinmingcode/article/details/50376035

tcp包长度

https://blog.csdn.net/lishanmin11/article/details/77045745

http 长度

https://blog.csdn.net/zerooffdate/article/details/78962818

http详解

https://segmentfault.com/a/1190000006689767#articleHeader8

https://blog.csdn.net/u012813201/article/details/70211255

websocket

https://www.jianshu.com/p/f666da1b1835

http://www.cnblogs.com/hustskyking/p/websocket-with-node.html

https://www.cnblogs.com/oshyn/p/3574497.html

浏览器开发-概述

想做个很简单浏览器,这样做可以,更加方便的web交互基础。不过很麻烦。这里留个档案吧。


浏览器内涵

 所谓的“浏览器内核”无非指的是一个浏览器最核心的部分——“Rendering Engine”,直译这个词汇叫做“渲染引擎”,不过我们也常称其为“排版引擎”、“解释引擎”。这个引擎的作用是帮助浏览器来渲染网页的内容,将页面内容和排版代码转换为用户所见的视图。

注:有时候我们所说的“浏览器内核”甚至“渲染引擎”,其实除了渲染引擎,也悄悄包含了javascript引擎,如WebKit,它由渲染引擎WebCore和javascript引擎JSCore组成。

常见的浏览器内核(或者说渲染引擎)有很多个,如Trident、Gecko、WebKit等等,不同的内核对网页编写语法的解释也有不同,进而导致同一个页面在不同内核的浏览器下显示出来的效果也会有所出入,这也是前端工程师需要让作品兼容各种浏览器的原因。

我们常常喜欢把浏览器内核与某浏览器名称直接挂钩起来,如IE内核、Chrome内核,其实是不全面的说法。比如Opera在7.0版本到12.16版本中采用的是独立研发的Presto引擎,但在后续跟随了Chrome的脚步加入了WebKit大本营,放弃了Presto;另外即使名称相同,但版本不同的引擎也可能存在较大差别。比如IE6使用的是Trident早期版本,存在许多bug,性能也较低。而最新的IE11所使用的Trident7.0版本已经可以支持WebGL(3D绘图标准)以及HTML5大部分标准。

下面按照各个主流浏览器,介绍下它们所使用的浏览器内核的历程。

Internet Explorer:

IE开发计划开始于1994年夏天,微软为抵抗当时主流的网景Netscape Navigator,要在Windows中开发适合自己的浏览器,但微软并没有时间从零开始。因此和Spyglass合作,于是IE从早期一款商业性的专利网页浏览器Spyglass Mosaic派生出来,虽然Spyglass Mosaic与NCSA Mosaic(首款应用得最广泛的网页浏览器)甚为相似,但Spyglass Mosaic则相对地较不出名并使用了NCSA Mosaic少量的源代码。

1996年,微软通过给予季度费用和部分收入从Spyglass中取得了Spyglass Mosaic的源代码和授权。从而使IE逐渐成为微软专属软件。它采用的排版引擎(俗称内核)为Trident。每一次新的IE版本发布,也标志着Trident内核版本号的提升。

下面是各Trident版本信息:

冷知识:除Trident之外,微软还有另一个网页浏览器排版引擎,称为Tasman,它是使用在「Internet Explorer for Mac」的排版引擎。相较于Trident,Tasman引擎对网页标准有较佳的支持,但微软自04年开始已经停止了Mac计算机版本的 Internet Explorer的开发。

Safari

        Safari是苹果公司开发的浏览器,使用了KDE(Linux桌面系统)的KHTML作为浏览器的运算核心,Safari所用浏览器内核的名称是大名鼎鼎的WebKit。 Safari在2003年1月7日首度发行测试版,并成为Mac OS X v10.3与之后版本的默认浏览器,也成为苹果其它系列产品的指定浏览器(也已支持Windows平台)。

        如上述可知,WebKit前身是KDE小组的KHTML引擎,可以说WebKit是KHTML的一个开源的分支。当年苹果在比较了Gecko和KHTML后,选择了后者来做引擎开发,是因为KHTML拥有清晰的源码结构和极快的渲染速度。

        需要了解的是,虽然我们称WebKit为浏览器内核(或浏览器引擎),但不太适合直接称之为我们开头提到的Rendering Engine(渲染引擎),因为WebKit本身主要是由两个引擎构成的,一个正是渲染引擎“WebCore”,另一个则是javascript解释引擎“JSCore”,它们均是从KDE的渲染引擎KHTML及javascript解释引擎KJS衍生而来。

        在2010年4月,苹果公司宣布了其浏览器引擎Webkit的最新项目 Webkit2。Webkit2的目标是实现独立进程与非阻断式API。

        WebKit可以说是苹果公司给开源世界的一大贡献,基于此开源引擎,衍生了多个WebKit分支,如下面要介绍的Chrome的浏览器引擎。

Chrome / Chromium

        谷歌Chrome/Chromium浏览器从08年创始至今一直使用苹果公司的WebKit作为浏览器内核原型,是WebKit的一个分支,我们可以称之为Chromium引擎(注意我们这里说的是Chromium引擎,而不是Chromium浏览器)。

        这里顺便介绍下Chrome和Chromium两个浏览器的区别——Chromium浏览器是谷歌为发展自家的浏览器Chrome而开启的计划,所以Chromium相当于Chrome的工程版或称实验版(尽管Chrome自身也有β版阶段),新功能会率先在Chromium上实现,待验证后才会应用在Chrome上。Chromium一天最多可以更新十几二十个版本,实验性的新特性都会现在这里放出,但是Chromium本身其实并不稳定;而Chrome总共有四个更新分支:Canary、Dev、Beta、Stable,稳定性依次增强。

        我们说回引擎。Chromium引擎虽然是属于WebKit的分支,却把WebKit的代码梳理得可读性提高很多,所以以前可能需要一天进行编译的代码,现在只要两个小时就能搞定。因此Chromium引擎和其它基于WebKit的引擎所渲染页面的效果也是有出入的。基于以上原因,有的地方会把Chromium引擎跟WebKit区分开来,有的地方则直接把Chromium引擎归为WebKit(比如维基百科),其实都有其道理。

        然而在13年发布的Chrome 28.0.1469.0版本开始,Chrome放弃Chromium引擎转而使用最新的Blink引擎(基于WebKit2——苹果公司于2010年推出的新的WebKit引擎),Blink对比上一代的引擎精简了代码、改善了DOM框架,也提升了安全性。

Opera

        Opera浏览器,是一款挪威Opera Software ASA公司制作的支持多页面标签式浏览的网络浏览器。是跨平台浏览器可以在Windows、Mac和Linux三个操作系统平台上运行。Opera浏览器创始于1995年4月,到2014年3月4日,官方发布的个人电脑用的最新版本为Opera20。

        Opera的一个里程碑作品是Opera7.0,因为它使用了Opera Software自主开发的Presto渲染引擎,取代了旧版Opera 4至6版本使用的Elektra排版引擎。

        Presto加入了动态功能,例如网页或其部分可随着DOM及Script语法的事件而重新排版。Presto在推出后不断有更新版本推出,使不少错误得以修正,以及阅读Javascript效能得以最佳化,并成为当时速度最快的引擎。

        然而为了减少研发成本,Opera在2013年2月宣布放弃Presto,转而跟随Chrome使用WebKit分支的Chromium引擎作为自家浏览器核心引擎。

        在Chrome与2013年推出Blink引擎(也是基于WebKit的分支)之后,Opera也紧跟其脚步表示将转而使用Blink作为浏览器核心引擎。

Firefox

        Mozilla Firefox是一个开源网页浏览器,原名是Firebird,2004年2月9日,Mozilla Firebird决定改称Mozilla Firefox。Firefox浏览器使用的是Gecko内核,其发展历程如下:

        1997年,网景收购了DigitalStyle。当时,网景浏览器在各方面的表现已经比不上她的主要竞争对手Internet Explorer。网景开始研发下一代的排版引擎,并期望把新的排版引擎应用于下一版本的网景浏览器上。

        1998年初,Mozilla计划开始执行。这个新的排版引擎名为Raptor,以开发源码的方式发放于互联网上。后来,因为商标问题,Raptor改名为NGLayout(即next generation layout之意)。而最后NGLayout就被网景重新命名为Gecko。

        2003年7月15日时代华纳解散了网景公司,大部分开发者被解雇。Mozilla基金会亦在当天成立,继续推动着Gecko的发展。时至今天,Gecko仍继续由Mozilla的雇员和义工所维护和发展。

        最后还是再谈谈javascript引擎(后面统称JS引擎)这东西。我们上述的渲染引擎主要是负责HTML、CSS以及其他一些东西的渲染,而JS引擎则主要负责对javascript的渲染,一个JS引擎的好坏决定了一个浏览器对脚本的加载和执行速度,也影响了其跑分。

        下方列出各种主流浏览器各自的JS引擎,了解下即可:

Firefox:

SpiderMonkey:第一款JavaScript引擎,由Brendan Eich在Netscape Communications时编写,用于Mozilla Firefox 1.0~3.0版本。

Rhino:由Mozilla基金会管理,开放源代码,完全以Java编写。

TraceMonkey:基于实时编译的引擎,其中部份代码取自Tamarin引擎,用于Mozilla Firefox 3.5~3.6版本。

JaegerMonkey:德文Jäger原意为猎人,结合追踪和组合码技术大幅提高性能,部分技术借凿了V8、JavaScriptCore、WebKit:用于Mozilla Firefox 4.0以上版本。

IonMonkey:可以对JavaScript编译后的结果进行优化,用于Mozilla Firefox 18.0以上版本。

OdinMonkey:可以对asm.js进行优化,用于Mozilla Firefox 22.0以上版本。

Chrome:

V8:开源,由Google丹麦开发,是Google Chrome的一部分。

注:我们上面提到Chrome是基于WebKit的分支,而WebKit又由渲染引擎“WebCore”和JS解释引擎“JSCore”组成,可能会让你搞不清V8和JSCore的关系。你可以这样理解——WebKit是一块主板,JSCore是一块可拆卸的内存条,谷歌实际上认为Webkit中的JSCore不够好,才自己搞了一个V8 JS引擎,这就是Chrome比Safari在某些JS测试中效率更高的原因。

IE:

Chakra:中文译名为查克拉,用于Internet Explorer 9的32位版本及IE10+。

Opera:

Linear A:用于Opera 4.0~6.1版本。

Linear B:用于Opera 7.0~9.2版本。

Futhark:用于Opera 9.5~10.2版本。

Carakan:由Opera软件公司编写,自Opera10.50版本开始使用。

其它:

KJS:KDE的ECMAScript/JavaScript引擎,最初由Harri Porten开发,用于KDE项目的Konqueror网页浏览器中。

Narcissus:开放源代码,由Brendan Eich编写(他也参与编写了第一个SpiderMonkey)。

Tamarin:由Adobe Labs编写,Flash Player 9所使用的引擎。

Nitro(原名SquirrelFish):为Safari 4编写。

网络原理-计算机网络详解-因特网与中国网络发展史

计算机网络与Internet发展历史

  • 1957年:苏联发射了人类第一颗人造地球卫星“ Sputnik”
  • 1958年:美国国防部(DoD)组建了高级研究计划局(ARPA)

1961-1972:早期分组交换原理的提出与应用

  • 1961: Kleinrock – 排队论证实分组交换的有效性
  • 1964: Baran – 分组交换应用于军事网络
  • 1967: ARPA(Advanced
    Research ProjectsAgency)提出ARPAnet构想
  • 1969: 第一个ARPAnet 结点运行:美国国防部委托开发ARPANET,进行联网研究
  • 1972:
    • ARPAnet公开演示
    • 第一个主机-主机协议NCP(Network Control Protocol)
    • 第一个e-mail程序
    • ARPAnet拥有15个结点
  • 1972年:招开计算机通信国际会议,称为ICCC(NCP网络协议)

1972-1980:网络互连,大量新型、私有网络的涌现

  • 1970:在夏威夷构建了ALOHAnet卫星网络
  • 1974: Cerf 与 Kahn – 提出网络互连体系结构
  • 1976: Xerox设计了以太网
  • 70’s后期:
    • 私有网络体系结构: DECnet,SNA, XNA
    • 固定长度分组交换 (ATM 先驱)
  • 1975: ARPAnet移交给美国国防部通信局管理
  • 1979: ARPAnet拥有200结点

1980-1990:新型网络协议与网络的激增

  • 1983年1月1日:所有连入ARPANET的主机向TCP/IP转变,即部署TCP/IP
  • 同年ARPANET分成MILNET和NSFNET
  • 1983: 部署TCP/IP
  • 1982: 定义了smtp电子邮件协议
  • 1983: 定义了DNS
  • 1985: 定义了FTP协议
  • 1988: TCP拥塞控制
  • 1990年,NSFNET彻底代替了ARPANET成为Internet的主干

新型国家级网络:CSnet, BITnet, NSFnet,Minitel(法国)

  • 1986: NSFnet初步形成了一个由骨干网、区域网和校园网组成的三级网络
  • 100,000台主机连接公
    共网络

1990, 2000’s: 商业化, Web, 新应用

  • 1990’s早期: ARPAnet退役
  • 1991: NSF解除NSFnet的商业应用限制(1995年退役),由私营企业经营
  • 1992:因特网协会ISOC成立
  • 1990s后期: Web应用
    • 超文本(hypertext) [Bush1945, Nelson 1960’s]
    • HTML, HTTP: Berners-Lee
    • 1994: Mosaic、 Netscape浏览器
    • 1990’s后期:Web开始商业应用
  • 1990’s后期 – 2000’s:
    • 更多极受欢迎的网络应用:即时消息系统(如QQ),P2P文件共享
  • 网络安全引起重视
  • 网络主机约达50000, 网络用户达1亿以上
  • 网络主干链路带宽达到Gbps

2005-今

  • ~7.5亿主机
    • 智能手机和平板电脑
  • 宽带接入的快速部署
  • 无处不在的高速无线接入快速增长
  • 出现在线社交网络:
    • Facebook: 很快拥有10亿用户
  • 服务提供商 (如Google, Microsoft)创建其自己的专用网络
    • 绕开Internet,提供“即时”接入搜索、 email等服务
    • 电子商务、大学、企业等开始在“云”中运行自己的服务(如, Amazon EC2)

中国最早期拨号访问国际互联网

从1986年开始,国内一些科研单位,通过长途电话拨号到欧洲的一些国家,进行联机数据库检索。不久,利用这些国家与Internet的连接,进行E-mail通信。
从1990年开始,国内的北京市计算机应用研究所、中科院高能物理研究所、电子部华北计算所、电子部石家庄第54研究所等科研单位,先后将自己的计算机与CNPAC(X.25)相连接。同时,利用欧洲国家的计算机作为网关,在X.25网与Internet之间进行转接,使得中国的CNPC科技用户可以与Internet用户进行E-mail通信。
1993年3月,中国科学院高能物理研究所(IHEP)为了支持国外科学家使用北京正负电子对撞机做高能物理实验,开通了一条64kbps国际数据信道,连接北京西郊的中科院高能所和美国斯坦福线性加速器中心(SLAC),运行DECnet协议,虽然不能提供完全的Internet功能,但经SAC机器的转接,可以与Internet进行Email通信。

 


一、建设NCFC时代背景

1989年,中国的改革开放进入了第二个十年。

美国在计算机网络领域已经经过了20年的发展,美国国防部高级研究计划局计算机网APAR网络于1968年就开始组建,APAR网络面向软件、硬件和数据库资源共享,采用分层的网络协议、包交换技术和分布式控制架构建设,这些技术思路影响着今天的网络体系结构。随着APAR网络向大学和商业的开放,信息技术和信息产业成为促进经济发展的引擎,美国国家科学基金会大力组织建设了科研网络环境和超级计算环境,使美国保持着信息科技和产业发展的领先地位。

1989年的圣诞假期,在欧洲核物理中心(CERN)工作的蒂姆·伯纳斯-李继续坚持着万维网梦想,为方便研究人员分享及更新讯息,制作完成了第一个万维网浏览器(同时也是编辑器)和第一个网页服务器。这一开发就是WWW技术的原型,当1993年4月30日CERN宣布万维网对任何人免费开放,并不收取任何费用时,WWW真正引爆了互联网的普及。

相比之下,我国电信市场还没有形成,连私人安装电话仍是颇为困难和奢侈的事情,计算机网络也仅有零星建设,没有互联,科研工作就更谈不上实质的数据资源和计算资源的共享。我国科研人员不得不通过传统邮政和邮电服务与国际同行进行交流,无法及时获取国际科技资料和最新成果,信息手段和时效短板严重影响着科技人员的研究视野、研究选题、计算效率和知识更新,严重制约了国家科技发展。在科研教育单位密集的中关村地区建设高性能的科学计算环境和高速计算机网络,并与国际Internet互联的需求十分迫切。

二、面向科研与教育信息化的NCFC项目建设

在信息化时代的大背景和我国科技与教育工作者对建设计算机网络的迫切需求形势下,当时的国家计委将NCFC列入“世界银行贷款重点学科发展项目”,并于1989年8月组织项目招标,确定中国科学院负责承担工程项目的建设任务。1989年10月,中国科学院按照国家计委的要求组建了NCFC管理委员会,时任中国科学院副院长的胡启恒同志担任管委会主任,国家计委、国家自然科学基金委、国家教委、清华大学和北京大学选派有关领导担任管委会成员,于1990年4月完成了工程建设的各项准备工作。

世界银行对NCFC项目内容界定为主干网,不包括大学和研究机构内部的园区网络,其建设目的是在中关村地区建立一个示范性的超级计算中心,并用高速网络将该地区的中国科学院院网、北京大学校园网、清华大学校园网与NCFC互联。使该地区的科技网人员能使用高速网络并通过网络使用超级计算机资源。

中国科学院院网(CASnet)、北京大学校园网(PUnet)和清华大学校园网(TUnet)则分别由三个单位各自出资、各自建设,国家计委对三个园区级网络进行了资金补助。

在世界银行、国家计委的支持下,该建设项目完成了NCFC主干网建设和三个单位园区网络建设,覆盖了中国科学院中关村地区附件的40多个研究所;部署和运行了64亿次浮点计算能力的超级计算机资源;更重要的是,NCFC项目衍生了计划外的重大成果——1994年4月20日,在国家计委的补助资金支持下,一条64K的国际卫星专线从中科院计算机网络中心通过美国Sprint公司连入Internet,首次实现了中国与Internet的全功能连接。从此中国被国际上正式承认为第77个真正拥有全功能Internet的国家。

在当时的历史条件下,NCFC工程解决了若干技术问题和政策问题,为后来的互联网络环境建设奠定了基础。

NCFC工程确定了以TCP/IP协议为主的技术路线。当时我国的计算机,较为常见的网络协议体系有TCP/IP、DECnet和OSI。要把使用不同网络协议体系的计算机互联,必须在网络通信协议上达成共识才能实现计算机间的信息互通。中科院计算机网络中心总体组坚持实用、开放的原则,明确了以TCP/IP协议为主,以OSI为发展方向,兼顾现有的其他协议的技术路线。这一设计思路,为NCFC网络顺利接入Internet做好了水到渠成的技术准备。

NCFC工程首次使用光纤线路建设计算机主干网络,通过网桥将中国科学院院网(CASnet)、北京大学校园网(PUnet)和清华大学校园网(TUnet)进行联网。综合多样性的技术手段和装备解决网络接入问题,对于校园和城域网络分别采用光纤和微波手段解决;对于长途网络采用X.25、卫星通信等通信手段接入;对于个人用户采用拨号方式接入,为用户接入工作提出了技术先进、综合、全面的解决方案。

=========================================================

CASnet 历史

CASnet 是中国科学院的全国性网络建设工程。该工程分为两部分,一部分为分院区域网络工程,另一部分是用远程信道将各分院区域网络及零星分布在其他城市的研究所互联到NFC网络中心的广域网工程。
CASnet的远程连接,又分为两期工程,第一期用X.25信道将全国3个城市连到北京,第二期以高速卫星信道代替X.25信道,并把更多的城市连到北京。1995年底,CASnet完成了将12个分院区域网及其他城市的研究所连到北京的广域网工程,连接了24个城市(包括北京)。作为第一步,早期的连接通过CHINAPAC实现,速率从9.6kbps到64kbps不等。目前,已将各主要分院的地区网络,用高速的卫星信道连到北京。零星分布的研究所仍暂时沿用ChinaPAC信道,不久将也用卫星连到北京。

=========================================================

技术人员很快发现,NCFC工程采用的网桥技术解决了CASnet、PUnet和TUnet之间的光纤联网,但是无法解决网络中广播风暴的影响,路由器的引入和部署变得十分必要和迫切。由于当时巴黎统筹委员会的限制使我国无法进口路由器,因此中科院计算机网络中心组织了技术人员自行开发路由器,并在NCFC主干网和中科院院网中部署应用,为提升网络可靠性发挥出关键作用,从而使NCFC与当时国外先进的网络同样可以高可靠性运行。

三、突破壁垒,实现与国际互联网全功能接入

Internet对当时的中国来说还是一个新生事物,和传统的电信业务有很大的不同。为了取得国家电信部门在国际专线租用方面的批准和支持,NCFC管委会和邮电部进行了多次的沟通,终于取得了国际专线资源支持。

当NCFC启动与国际联网的时候,美国方面处于政治和安全方面的原因,不接纳我国接入Internet。1993年中科院计算机网络中心钱华林等同志赴美与sprint公司商谈落实了与Internet联网方案,并根据公共网络服务要求,制定了NCFC“准用政策”(AUP),在报经国务院邹家华副总理等有关领导同意后,NCFC管委会主任胡启恒同志在参加美国华盛顿举行的中美科技合作联合委员会第六次会议期间,就NCFC与Internet联网问题,与NSF官员进行商谈,美国同意遵守NSFNET(美国科研与教育骨干网)和NCFC“准用政策”的条件下,实现NCFC与美国NSF主干网连接。随后,在1994年3月开通了国际卫星专线,4月中美两侧路由器开通,同时,在中科院计算机网络中心建立了代表Internet中国顶级域名的.cn服务器、邮件服务器、文件服务器等一系列网络服务器。

  

  中国第一台.CN域名服务器

  随后,中科院计算机网络中心进一步完成了在InterNIC的注册,建立了与国际IneterNIC和APNIC规范的业务联系,并于1994年10月建成了NIC(网络信息中心)和NOC(网络运行中心),对国内外用户服务。自此,中国互联网系统地、整体地展现于世界。

四、NCFC建设的后续演进和发展

NCFC项目圆满完成了网络建设目标和超级计算机建设目标,并实现了与Internet联网。

中国科学院在NCFC和CASnet的基础上,以服务科研信息化为定位和发展方向,建设中国科技网(CSTNET)。经过不断的建设,中国科技网已成为承载国家超级计算资源、科学数据资源、服务国家科技创新的科研信息化技术设施,取得了令人瞩目的应用成果和社会效益。中国科技网具有向全国提供IPv4和IPv6双栈接入的7×24服务能力,提供电子邮件、视频会议、科研协同环境、网络管理、网络安全等丰富的互联网服务产品,在我国嫦娥工程、国际联合天文观测、高能物理海量数据传输、大型科研装置数据传输、野外台站联网观测和应急救灾等方面提供高性能网络支撑和技术支持。

=======================================================

CSTNet历史

CSTNet 是以中国科学院的NCFC及CASnet为基础,连接了中国科学院以外的一批中国科技单位而构成的网络。目前接入CSTNet的单位有农业、林业、医学、电力、地震、气象、铁道、电子、航空航天、环境保护等近30个科研部门及国家自然科学基金委、国家专利局等科技管理部门。目前,CSTNet有2Mbps的信道连到美国,64Kbps的信道连到法国,64Kbps的信道连到日本。【很早之前的历史资料了】
CSTNet为非盈利、公益性的网络,主要为科技用户、科技管理部门及与科技有关的政府部门服务。

=======================================================

由NCFC发展起来的中国互联网络信息中心(CNNIC)行使着国家互联网络信息中心的职责。经过长期的建设和开拓,CNNIC已经成为国家网络基础资源的运行管理和服务机构、国家网络基础资源的技术研发和安全中心、互联网发展研究力量、互联网开放合作和技术交流平台,促进科研成果转化和孵化,服务中国互联网事业发展。

更重要的是,NCFC项目的建成吹响了中国互联网时代的号角。NCFC项目1998年获得中国科学院科技进步特等奖;国家统计局将“国家计算与网络设施(NCFC)实现国内国际联网”列为1994年度国家重大科技成就之一;人民日报将“中国国家计算与网络设施(NCFC)实现国内国际联网成功”列为1994年中国十大科技新闻之一。作为一个示范性网络,NCFC建设在中国掀起了一个发展Internet的热潮,国内先后建设成了中国科技网CSTNET、中国公用计算机互联网CHINANET、中国教育和科研计算机网CERNET和中国金桥信息网CHINAGBN,也就是早期的中国四大互联网络。

今天,生活在互联网时代的我们重新梳理20年前的历史,不仅要向当时的建设者们致以崇高的敬意,更要有同样的勇气和智慧迎接互联网时代的新挑战。作为中国互联网发源地的中科院计算机网络信息中心,现今已经承担起了历史赋予的新使命:致力于中国科学院科研信息化和管理信息化的研发、支撑与服务。如果您到中科院计算机网络信息中心来,依然可以看到当初接入Internet的机房,也可看到我国第一台路由器、第一台CN域名服务器。面对这些历史物件,再转身看看中科院信息化基础设施机房里成排的服务器、大型的高性能计算机,我们无法不慨叹信息时代发展的“火箭速度”,并且暗自庆幸我们正置身于这个“一切皆有可能”的信息社会。

 

 


参考:

http://www.cas.cn/kxcb/kpwz/201404/t20140419_4093686.shtml

https://baike.baidu.com/item/CSTNET

网络原理-计算机网络详解-传输层之TCP协议

一、TCP 协议的作用

互联网由TCP/IP协议族构成。TCP 只是其中的一层,有着自己的分工。

(图片说明:TCP 是以太网协议和 IP 协议的上层协议,也是应用层协议的下层协议。)

最底层的以太网协议(Ethernet)规定了电子信号如何组成数据帧(frame),解决了子网内部的点对点通信。

(图片说明:以太网协议解决了局域网的点对点通信。)

但是,以太网协议不能解决多个局域网如何互通,这由 IP 协议解决。

(图片说明:IP 协议可以连接多个局域网。)

IP 协议定义了一套自己的地址规则,称为 IP 地址。它实现了路由功能,允许某个局域网的 A 主机,向另一个局域网的 B 主机发送消息。

(图片说明:路由器就是基于 IP 协议。局域网之间要靠路由器连接。)

路由的原理很简单。市场上所有的路由器,背后都有很多网口,要接入多根网线。路由器内部有一张路由表,规定了 A 段 IP 地址走出口一,B 段地址走出口二,……通过这套”指路牌”,实现了数据包的转发。

(图片说明:本机的路由表注明了不同 IP 目的地的数据包,要发送到哪一个网口(interface)。)

IP 协议只是一个地址协议,并不保证数据包的完整。如果路由器丢包(比如缓存满了,新进来的数据包就会丢失),就需要发现丢了哪一个包,以及如何重新发送这个包。这就要依靠 TCP 协议。

简单说,TCP 协议的作用是,保证数据通信的完整性和可靠性,防止丢包。

二、TCP 报文段的大小

MTU最大传输单元,这个最大传输单元实际上和链路层协议有着密切的关系,EthernetII帧的结构DMAC+SMAC+Type+Data+CRC由于以太网传输电气方面的限制,每个以太网帧都有最小的大小64bytes最大不能超过1518bytes,对于小于或者大于这个限制的以太网帧我们都可以视之为错误的数据帧,一般的以太网转发设备会丢弃这些数据帧。

由于以太网EthernetII最大的数据帧是1518Bytes这样,刨去以太网帧的帧头(DMAC目的MAC地址48bit=6Bytes+SMAC源MAC地址48bit=6Bytes+Type域2bytes)14Bytes和帧尾CRC校验部分4Bytes那么剩下承载上层协议的地方也就是Data域最大就只能有1500Bytes这个值我们就把它称之为MTU。

以太网数据包(packet)由于环境限制,最大值是固定的,最初协议是1518字节,后来新协议是1522字节。但是MTU 仍是 1500Bytes。

为了允许一些使用以太II版本的数据报和一些使用802.3封装的最初版本的数据包能够在同一个以太网段使用,以太类型值必须大于等于1536(0x0600)。这个值比802.3数据包的最大长度1500byte (0x05DC)要更大。因此如果这个字段的值大于等于1536,则这个帧是以太II帧,而那个字段是类型字段。否则(小于1500而大于46字节),他是一个IEEE 802.3帧,而那个字段是长度字段。1500~1536(不包含)的数值未定义。因为网络环境 MTU选择是1500【即以太网帧最大负载是1500字节】,所以我们上网用的以太网帧 应该是 802.3帧。

来自维基百科

802.3 以太网帧结构
前导码 帧开始符 MAC 目标地址 MAC 源地址 802.1Q 标签 (可选) 以太类型 负载 冗余校验 帧间距
10101010 7个octet 10101011 1个octet 6 octets 6 octets (4 octets) 2 octets 46–1500 octets 4 octets 12 octets
64–1522 octets
72–1530 octets
84–1542 octets

IP 数据包在以太网数据包的负载里面,它也有自己的头信息,最少需要20字节,所以 IP 数据包的负载最多为1480字节。

(图片说明:IP 数据包在以太网数据包里面,TCP 报文段在 IP 数据包里面。)

TCP 报文段在 IP 数据包的负载里面。它的头信息最少也需要20字节,因此 TCP 报文段的最大负载是 1480 – 20 = 1460 字节。由于 IP 和 TCP 协议往往有额外的头信息,所以 TCP 负载实际为1400字节左右。

因此,一条1500字节的信息需要两个 TCP报文段。HTTP/2 协议的一大改进, 就是压缩 HTTP 协议的头信息,使得一个 HTTP 请求可以放在一个 TCP 报文段里面,而不是分成多个,这样就提高了速度。

(图片说明:以太网数据帧的负载是1500字节,TCP 报文段的负载在1400字节左右。)

三、TCP报文段的格式

图释:

抓包过后才发现,ip数据包首部没有添加可选项,就直接装载 tcp 数据了。

各个段位说明:

  • 源端口和目的端口:  各占 2 字节.端口是传输层与应用层的服务接口.传输层的复用和分用功能都要通过端口才能实现
  • 序号:  占 4 字节。用于对字节流进行编号,例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。
  • 确认号:  占 4 字节,期望收到的下一个报文段的序号。例如 B 正确收到 A 发送来的一个报文段,序号为 501,携带的数据长度为 200 字节,因此 B 期望下一个报文段的序号为 701,B 发送给 A 的确认报文段中确认号就为 701。
  • 数据偏移/首部长度:  占 4 位,指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。“数据偏移”的单位是 32 位字(以 4 字节为计算单位)
  • 保留:  占 6 位,保留为今后使用,但目前应置为 0
  • 紧急URG:  当 URG=1 时,表明紧急指针字段有效.它告诉系统此报文段中有紧急数据,应尽快传送(相当于高优先级的数据)
  • 确认ACK:  只有当 ACK=1 时确认号字段才有效。当 ACK=0 时,确认号无效。TCP 规定,在连接建立后所有传送的报文段都必须把 ACK 置 1。
  • PSH(PuSH):  接收 TCP 收到 PSH = 1 的报文段,就尽快地交付接收应用进程,而不再等到整个缓存都填满了后再向上交付
  • RST (ReSeT):  当 RST=1 时,表明 TCP 连接中出现严重差错(如由于主机崩溃或其他原因),必须释放连接,然后再重新建立运输连接
  • 同步 SYN:  在连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。
  • 终止 FIN:  用来释放一个连接。FIN=1 表明此报文段的发送端的数据已发送完毕,并要求释放运输连接
  • 窗口:      窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。
  • 检验和:  占 2 字节.检验和字段检验的范围包括首部和数据这两部分.在计算检验和时,要在 TCP 报文段的前面加上 12 字节的伪首部
  • 紧急指针:  占 16 位,指出在本报文段中紧急数据共有多少个字节(紧急数据放在本报文段数据的最前面)
  • 选项:  长度可变.TCP 最初只规定了一种选项,即最大报文段长度 MSS.MSS 告诉对方 TCP:“我的缓存所能接收的报文段的数据字段的最大长度是 MSS 个字节.” [MSS(Maximum Segment Size)是 TCP 报文段中的数据字段的最大长度.数据字段加上 TCP 首部才等于整个的 TCP 报文段]
  • 填充:  这是为了使整个首部长度是 4 字节的整数倍
  • 其他选项:
    • 窗口扩大:  占 3 字节,其中有一个字节表示移位值 S.新的窗口值等于TCP 首部中的窗口位数增大到(16 + S),相当于把窗口值向左移动 S 位后获得实际的窗口大小
    • 时间戳:  占10 字节,其中最主要的字段时间戳值字段(4字节)和时间戳回送回答字段(4字节)
    • 选择确认:  接收方收到了和前面的字节流不连续的两2字节.如果这些字节的序号都在接收窗口之内,那么接收方就先收下这些数据,但要把这些信息准确地告诉发送方,使发送方不要再重复发送这些已收到的数据

四、TCP报文段特点

数据单位

TCP 传送的数据单位协议是 TCP 报文段(segment)

特点

TCP 是面向连接的传输层协议
每一条 TCP 连接只能有两个端点(endpoint),每一条 TCP 连接只能是点对点的(一对一)
TCP 提供可靠交付的服务
TCP 提供全双工通信
面向字节流

注意

TCP 对应用进程一次把多长的报文发送到TCP 的缓存中是不关心的
TCP 根据对方给出的窗口值和当前网络拥塞的程度来决定一个报文段应包含多少个字节(UDP 发送的报文长度是应用进程给出的)
TCP 可把太长的数据块划分短一些再传送.TCP 也可等待积累有足够多的字节后再构成报文段发送出去
每一条 TCP 连接有两个端点
TCP 连接的端点不是主机,不是主机的IP 地址,不是应用进程,也不是传输层的协议端口.TCP 连接的端点叫做套接字(socket)或插口


五、TCP报文段的编号(SEQ)

一个报文段1400字节,那么一次性发送大量数据,就必须分成多个报文段(segment)。比如,一个 10MB 的文件,需要发送7100多个包。

发送的时候,TCP 协议为每个报文段编号(sequence number,简称 SEQ),以便接收的一方按照顺序还原。万一发生丢分段,也可以知道丢失的是哪一个报文段。

第一个报文段的编号是一个随机数。为了便于理解,这里就把它称为1号报文段。假定这个报文段的负载长度是100字节,那么可以推算出下一个报文段的编号应该是101。这就是说,每个报文段都可以得到两个编号:自身的编号,以及下一个报文段的编号。接收方由此知道,应该按照什么顺序将它们还原成原始文件。

(图片说明:当前分段的编号是45943,下一个数据分段的编号是46183,由此可知,这个分段的负载是240字节。)

六、TCP 报文段的组装

收到 TCP 报文段以后,组装还原是操作系统完成的。应用程序不会直接处理 TCP 报文段。

对于应用程序来说,不用关心数据通信的细节。除非线路异常,收到的总是完整的数据。应用程序需要的数据放在 TCP 报文段里面,有自己的格式(比如 HTTP 协议)。

TCP 并没有提供任何机制,表示原始文件的大小,这由应用层的协议来规定。比如,HTTP 协议就有一个头信息Content-Length,表示信息体的大小。对于操作系统来说,就是持续地接收 TCP 报文段,将它们按照顺序组装好,一个分段都不少。

操作系统不会去处理 TCP 报文段里面的数据。一旦组装好 TCP 报文段,就把它们转交给应用程序。TCP 报文段里面有一个端口(port)参数,就是用来指定转交给监听该端口的应用程序。

(图片说明:系统根据 TCP 报文段里面的端口,将组装好的数据转交给相应的应用程序。上图中,21端口是 FTP 服务器,25端口是 SMTP 服务,80端口是 Web 服务器。)

应用程序收到组装好的原始数据,以浏览器为例,就会根据 HTTP 协议的Content-Length字段正确读出一段段的数据。这也意味着,一次 TCP 通信可以包括多个 HTTP 通信。


七、建立连接和断开连接过程

报文段的发送时机

TCP 维持一个变量,它等于最大报文段长度 MSS.只要缓存中存放的数据达到 MSS 字节时,就组装成一个 TCP 报文段发送出去
由发送方的应用进程指明要求发送报文段,即 TCP 支持的推送(push)操作
发送方的一个计时器期限到了,这时就把当前已有的缓存数据装入报文段(但长度不能超过 MSS)发送出去

发送TCP请求客户端

三次连接四次挥手

三个阶段:

  • 连接建立:
    • 图释:

    • 步骤:
      • A 的 TCP 向 B 发出连接请求报文段,其首部中的同步位 SYN = 1,并选择序号 seq = x,表明传送数据时的第一个数据字节的序号是 x
      • B 的 TCP 收到连接请求报文段后,如同意,则发回确认(B 在确认报文段中应使 SYN = 1,使 ACK = 1,其确认号ack = x﹢1,自己选择的序号 seq = y)
      • A 收到此报文段后向 B 给出确认,其 ACK = 1,确认号 ack = y﹢1(A 的 TCP 通知上层应用进程,连接已经建立,B 的 TCP 收到主机 A 的确认后,也通知其上层应用进程:TCP 连接已经建立)
  • 数据传送
  • 连接释放:
    • 图释:

    • 步骤:
      • 数据传输结束后,通信的双方都可释放连接.现在 A 的应用进程先向其 TCP 发出连接释放报文段,并停止再发送数据,主动关闭 TCP 连接(A 把连接释放报文段首部的 FIN = 1,其序号seq = u,等待 B 的确认)
      • B 发出确认,确认号 ack = u+1,而这个报文段自己的序号 seq = v(TCP 服务器进程通知高层应用进程.从 A 到 B 这个方向的连接就释放了,TCP 连接处于半关闭状态.B 若发送数据,A 仍要接收)
      • 若 B 已经没有要向 A 发送的数据,其应用进程就通知 TCP 释放连接
      • A 收到连接释放报文段后,必须发出确认,在确认报文段中 ACK = 1,确认号 ack=w﹢1,自己的序号 seq = u + 1
    • 注意:

TCP 连接必须经过时间 2MSL 后才真正释放掉(2MSL 的时间的用意 — 为了保证 A 发送的最后一个 ACK 报文段能够到达 B.防止 “已失效的连接请求报文段”出现在本连接中.A 在发送完最后一个 ACK 报文段后,再经过时间 2MSL,就可以使本连接持续的时间内所产生的所有报文段,都从网络中消失.这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段)

    • 发现丢失确认时候的处理:

三个问题:

  • 要使每一方能够确知对方的存在
  • 要允许双方协商一些参数(如最大报文段长度,最大窗口大小,服务质量等)
  • 能够对运输实体资源(如缓存大小,连接表中的项目等)进行分配

四次挥手 :

A:我这边传完了,你那边收接收完了没?B:我这边接收完了。A就不传输信息了。

B:我这边传完了,你那边收接收完了没?A:我这边接收完了。B就不传输信息了。


七、滑动窗口(发送窗口-接收窗口-拥塞窗口)

滑动窗口

图释:

特点:

  • 以字节为单位的滑动窗口
  • A 的发送窗口并不总是和 B 的接收窗口一样大(因为有一定的时间滞后)

要求:

  • TCP 标准没有规定对不按序到达的数据应如何处理.通常是先临时存放在接收窗口中,等到字节流中所缺少的字节收到后,再按序交付上层的应用进程
  • TCP 要求接收方必须有累积确认的功能,这样可以减小传输开销

具体实现: 


七、拥塞避免

服务器发送数据包,当然越快越好,最好一次性全发出去。但是,发得太快,就有可能丢包。带宽小、路由器过热、缓存溢出等许多因素都会导致丢包。线路不好的话,发得越快,丢得越多。

最理想的状态是,在线路允许的情况下,达到最高速率。但是我们怎么知道,对方线路的理想速率是多少呢?

1、慢开始算法

TCP 协议为了做到效率与可靠性的统一,设计了一个慢启动(slow start)机制。开始的时候,发送得较慢,然后根据丢报文段的情况,调整速率:如果不丢报文段,就加快发送速度;如果丢报文段,就降低发送速度。

Linux 内核里面设定了(常量TCP_INIT_CWND),刚开始通信的时候,发送方一次性发送10个报文段,即”发送窗口”的大小为10。然后停下来,等待接收方的确认,再继续发送。

默认情况下,接收方每收到两个 TCP 报文段,就要发送一个确认消息。”确认”的英语是 acknowledgement,所以这个确认消息就简称 ACK。

ACK 携带两个信息。

  • 期待要收到下一个数据包的编号
  • 接收方的接收窗口的剩余容量

发送方有了这两个信息,再加上自己已经发出的报文段的最新编号,就会推测出接收方大概的接收速度,从而降低或增加发送速率。这被称为”发送窗口”,这个窗口的大小是可变的。

(图片说明:每个 ACK 都带有下一个报文段的编号,以及接收窗口的剩余容量。双方都会发送 ACK。)

注意,由于 TCP 通信是双向的,所以双方都需要发送 ACK。两方的窗口大小,很可能是不一样的。而且 ACK 只是很简单的几个字段,通常与数据合并在一个报文段里面发送。

(图片说明:上图一共4次通信。第一次通信,A 主机发给B 主机的报文段编号是1,长度是100字节,因此第二次通信 B 主机的 ACK 编号是 1 + 100 = 101,第三次通信 A 主机的报文段编号也是 101。同理,第二次通信 B 主机发给 A 主机的报文段编号是1,长度是200字节,因此第三次通信 A 主机的 ACK 是201,第四次通信 B 主机的报文段编号也是201。)

即使对于带宽很大、线路很好的连接,TCP 也总是从10个报文段开始慢慢试,过了一段时间以后,才达到最高的传输速率。这就是 TCP 的慢启动。


慢开始算法:

  • 在主机刚刚开始发送报文段时可先设置拥塞窗口 cwnd = 1,即设置为一个最大报文段 MSS 的数值
  • 在每收到一个对新的报文段的确认后,将拥塞窗口加 1,即增加一个 MSS 的数值
  • 使用慢开始算法后,每经过一个传输轮次(往返时间 RTT),拥塞窗口 cwnd 就加倍

2、拥塞避免算法:

拥塞窗口 cwnd 缓慢地增大,即每经过一个往返时间 RTT 就把发送方的拥塞窗口 cwnd 加 1,使拥塞窗口 cwnd 按线性规律缓慢增长

3、慢开始门限 ssthresh 的用法:

  • 当 cwnd < ssthresh 时,使用慢开始算法
  • 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法
  • 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞避免算法

4、网络出现拥塞时(其根据就是没有按时收到确认):

  • 就要把慢开始门限 ssthresh 设置为出现拥塞时的发送方窗口值的一半(但不能小于2)
  • 然后把拥塞窗口 cwnd 重新设置为 1.执行慢开始算法

八、拥塞处理

拥塞窗口:

含义:

拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化.发送方让自己的发送窗口等于拥塞窗口.如再考虑到接收方的接收能力,则发送窗口还可能小于拥塞窗口

发送方控制拥塞窗口的原则:

只要网络没有出现拥塞,拥塞窗口就再增大一些,以便把更多的分组发送出去.但只要网络出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数

乘法减小:

是指不论在慢开始阶段还是拥塞避免阶段,只要出现一次超时(即出现一次网络拥塞),就把慢开始门限值 ssthresh 设置为当前的拥塞窗口值乘以 0.5

加法增大:

是指执行拥塞避免算法后,在收到对所有报文段的确认后(即经过一个往返时间),就把拥塞窗口 cwnd增加一个 MSS 大小,使拥塞窗口缓慢增大,以防止网络过早出现拥塞

快重传:

每一个TCP报文段都带有下一个报文段的编号。如果下一个报文段没有收到,那么 ACK 的编号就不会发生变化。

举例来说,现在收到了4号报文段,但是没有收到5号报文段。ACK 就会记录,期待收到5号报文段。过了一段时间,5号报文段收到了,那么下一轮 ACK 会更新编号。如果5号报文段还是没收到,但是收到了6号报文段或7号报文段,那么 ACK 里面的编号不会变化,总是显示5号报文段。这会导致大量重复内容的 ACK。

如果发送方发现收到三个连续的重复 ACK,或者超时了还没有收到任何 ACK,就会确认丢失报文段,即5号报文段遗失了,从而再次发送这个报文段。通过这种机制,TCP 保证了不会有报文段丢失。

(图片说明:Host B 没有收到100号报文段,会连续发出相同的 ACK,触发 Host A 重发100号报文段。)

快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认.这样做可以让发送方及早知道有报文段没有到达接收方,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段

快恢复:

当发送端收到连续三个重复的确认时,就执行“乘法减小”算法,把慢开始门限 ssthresh 减半.但接下去不执行慢开始算法

发送窗口的上限值:

发送方的发送窗口的上限值应当取为接收方窗口 rwnd 和拥塞窗口 cwnd 这两个变量中较小的一个,即应按以下公式确定:
发送窗口的上限值 Min [rwnd, cwnd]

    • 当 rwnd < cwnd 时,是接收方的接收能力限制发送窗口的最大值
    • 当 cwnd < rwnd 时,则是网络的拥塞限制发送窗口的最大值

九、报文段的遗失处理-自动重传

TCP 协议可以保证数据通信的完整性,这是怎么做到的?

自动重传请求ARQ

定义:

可靠传输协议常称为自动重传请求ARQ (Automatic Repeat reQuest)

累积确认:

  • 定义:  接收方一般采用累积确认的方式.即不必对收到的分组逐个发送确认,而是对按序到达的最后一个分组发送确认,这样就表示:到这个分组为止的所有分组都已正确收到了
  • 优点:  容易实现,即使确认丢失也不必重传
  • 缺点:  不能向发送方反映出接收方已经正确收到的所有分组的信息

Go-back-N(回退N):

如果发送方发送了前 5 个分组,而中间的第 3 个分组丢失了.这时接收方只能对前两个分组发出确认.发送方无法知道后面三个分组的下落,而只好把后面的三个分组都再重传一次

具体实现

说明:

  • TCP 连接的每一端都必须设有两个窗口 一个发送窗口和一个接收窗口
  • TCP 可靠传输机制用字节的序号进行控制.TCP 所有的确认都是基于序号而不是基于报文段
  • TCP 两端的四个窗口经常处于动态变化之中
  • TCP连接的往返时间 RTT 也不是固定不变的.需要使用特定的算法估算较为合理的重传时间

图释:

确认丢失和确认迟到

超时重传时间选择

具体实现:

TCP 每发送一个报文段,就对这个报文段设置一次计时器.只要计时器设置的重传时间到但还没有收到确认,就要重传这一报文段

加权平均往返时间:

做法:

TCP 保留了 RTT 的一个加权平均往返时间 RTTS(这又称为平滑的往返时间),第一次测量到 RTT 样本时,RTTS 值就取为所测量到的 RTT 样本值.以后每测量到一个新的 RTT 样本,就按下式重新计算一次 RTTS:

公式:

新的 RTTS = ( 1 – α)×(旧的 RTTS)+α(新的 RTT 样本)

说明:

式中,0 ≤ α< 1.若α很接近于零,表示 RTT 值更新较慢若选择 α 接近于1,则表示 RTT 值更新较快
RFC 2988 推荐的 α 值为 1/8,即 0.125

超时重传时间RTO:

RTO 应略大于上面得出的加权平均往返时间 RTTS.
RFC 2988 建议使用下式计算 RTO:

RTO=RTTS + 4×RTTD

RTTD 是 RTT 的偏差的加权平均值
RFC 2988 建议这样计算 RTTD.第一次测量时,RTTD 值取为测量到的 RTT 样本值的一半.在以后的测量中,则使用下式计算加权平均的 RTTD:

新的 RTTD = (1-β)×(旧的RTTD)+β×|RTTS﹣新的 RTT 样本|

β是个小于 1 的系数,其推荐值是 1/4,即 0.25
在计算平均往返时间 RTT 时,只要报文段重传了,就不采用其往返时间样本

修正的Karn算法:

报文段每重传一次,就把 RTO 增大一些:

新的 RTO= γ×(旧的 RTO)

系数γ 的典型值是 2
当不再发生报文段的重传时,才根据报文段的往返时延更新平均往返时延 RTT 和超时重传时间 RTO 的数值

持续计时器

  • TCP 为每一个连接设有一个持续计时器
  • 只要 TCP 连接的一方收到对方的零窗口通知,就启动持续计时器
  • 若持续计时器设置的时间到期,就发送一个零窗口探测报文段(仅携带 1 字节的数据),而对方就在确认这个探测报文段时给出了现在的窗口值
  • 若窗口仍然是零,则收到这个报文段的一方就重新设置持续计时器
  • 若窗口不是零,则死锁的僵局就可以打破了

九、缓存控制

发送缓存

发送缓存用来暂时存放:

  • 发送应用程序传送给发送方 TCP 准备发送的数据
  • TCP 已发送出但尚未收到确认的数据

图释:

接收缓存

接收缓存用来暂时存放:

  • 按序到达的、但尚未被接收应用程序读取的数据;
  • 不按序到达的数据

 图释:

 

 


参考:

http://www.cnblogs.com/kzang/articles/2582957.html

http://www.ruanyifeng.com/blog/2017/06/tcp-protocol.html

https://blog.csdn.net/u014222687/article/details/55002177

网络原理-计算机网络详解-传输层概述

我们这里只讲TCP/IP 网络模型的传输层协议,传输层协议有TCP协议和UDP协议。

一、传输层

传输层的作用

TCP提供可靠的通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输。

传输层定义

IP首部有一个协议字段,用来标识网络层(IP)的上一层所采用的是哪一种传输层协议。根据这个字段的协议号,就可以识别IP传输的数据部分究竟是TCP的内容还是UDP的内容。

同样,传输层的TCP和UDP,为了识别自己所传输的数据部分究竟应该发给哪个应用,也设定了这样一个编号。

在TCP/IP通信中需要指定“应用程序”。而传输层必须指出这个具体的程序,为了实现这一功能,使用端口号这样一种识别码。根据端口号可以识别在传输层上一层的应用层中所要进行处理的具体程序。

通信处理

服务端程序在UNIX系统当中叫做守护进程。例如HTTP的服务端程序是httpd(HTTP守护进程),而ssh的服务端程序是sshd(SSH守护进程)。UNIX中并不需要将这些守护进程逐个启动,而是启动一个可以代表它们接收客户端请求的inetd(互联网守护进程)服务程序即可。它是一种超级守护进程。该超级守护进程收到客户端请求以后会创建(fork)新的进程并转换(exec)为sshd等各个守护进程。

确认一个请求究竟发给的是哪个服务端(守护进程),可以通过所收到数据包的目标端口号轻松识别。当收到TCP的建立连接请求时,如果目标端口为22,则转给sshd,如果是80则转给httd。然后,这些守护进程会继续对该连接上的通信传输进行处理。

传输协议TCP、UDP通过接收数据中的目标端口识别目标处理程序。以下图为例,传输协议的数据将被传递给HTTP、TELNET以及FTP等应用层协议。

HTTP连接请求:

通过IP地址、端口号、协议号进行通信识别

TCP/IP或UDP/IP通信中通常采用5个信息来识别一个通信。它们是“源IP地址”、“目标IP地址”、“协议号”、“源端口号”、“目标端口号”。只要其中某一项不同,则被认为是其他通信。

 

二、SOCKET的用处

Socket是什么呢?
Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

大白话:我们编写的应用层协议:http 、ftp、smtp 都是调用socket 接口实现的。

三、TCP与UDP简介

TCP(Transmission Control Protocol,传输控制协议)是基于连接的协议,也就是说,在正式收发数据前,必须和对方建立可靠的连接。一个TCP连接必须要经过三次“对话”才能建立起来,其中的过程非常复杂,我们这里只做简单、形象的介绍,你只要做到能够理解这个过程即可。我们来看看这三次对话的简单过程:主机A向主机B发出连接请求数据包:“我想给你发数据,可以吗?”,这是第一次对话;主机B向主机A发送同意连接和要求同步(同步就是两台主机一个在发送,一个在接收,协调工作)的数据包:“可以,你什么时候发?”,这是第二次对话;主机A再发出一个数据包确认主机B的要求同步:“我现在就发,你接着吧!”,这是第三次对话。三次“对话”的目的是使数据包的发送和接收同步,经过三次“对话”之后,主机A才向主机B正式发送数据。

UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是面向非连接的协议,它不与对方建立连接,而是直接就把数据包发送过去!
UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境。比如,我们经常使用“ping”命令来测试两台主机之间TCP/IP通信是否正常,其实“ping”命令的原理就是向对方主机发送UDP数据包,然后对方主机确认收到数据包,如果数据包是否到达的消息及时反馈回来,那么网络就是通的。例如,在默认状态下,一次“ping”操作发送4个数据包(如图2所示)。大家可以看到,发送的数据包数量是4包,收到的也是4包(因为对方主机收到后会发回一个确认收到的数据包)。这充分说明了UDP协议是面向非连接的协议,没有建立连接的过程。正因为UDP协议没有连接的过程,所以它的通信效果高;但也正因为如此,它的可靠性不如TCP协议高。QQ就使用UDP发消息,因此有时会出现收不到消息的情况。

四、TCP与UDP的区别

TCP与UDP基本区别
1.基于连接与无连接
2.TCP要求系统资源较多,UDP较少;
3.UDP程序结构较简单
4.流模式(TCP)与数据报模式(UDP);
5.TCP保证数据正确性,UDP可能丢包
6.TCP保证数据顺序,UDP不保证

UDP应用场景:
1.面向数据报方式
2.网络数据大多为短消息
3.拥有大量Client
4.对数据安全性无特殊要求
5.网络负担非常重,但对响应速度要求高

具体编程时的区别
1.socket()的参数不同
2.UDP Server不需要调用listen和accept
3.UDP收发数据用sendto/recvfrom函数
4.TCP:地址信息在connect/accept时确定
5.UDP:在sendto/recvfrom函数中每次均 需指定地址信息
6.UDP:shutdown函数无效

编程区别
通常我们在说到网络编程时默认是指TCP编程,即用前面提到的socket函数创建一个socket用于TCP通讯,函数参数我们通常填为SOCK_STREAM。即socket(PF_INET, SOCK_STREAM, 0),这表示建立一个socket用于流式网络通讯。
SOCK_STREAM这种的特点是面向连接的,即每次收发数据之前必须通过connect建立连接,也是双向的,即任何一方都可以收发数据,协议本身提供了一些保障机制保证它是可靠的、有序的,即每个包按照发送的顺序到达接收方。

而SOCK_DGRAM这种是User Datagram Protocol协议的网络通讯,它是无连接的,不可靠的,因为通讯双方发送数据后不知道对方是否已经收到数据,是否正常收到数据。任何一方建立一个socket以后就可以用sendto发送数据,也可以用recvfrom接收数据。根本不关心对方是否存在,是否发送了数据。它的特点是通讯速度比较快。大家都知道TCP是要经过三次握手的,而UDP没有。

基于上述不同,UDP和TCP编程步骤也有些不同,如下:

TCP: 
TCP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt(); * 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、开启监听,用函数listen();
5、接收客户端上来的连接,用函数accept();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;
8、关闭监听;

TCP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置要连接的对方的IP地址和端口等属性;
5、连接服务器,用函数connect();
6、收发数据,用函数send()和recv(),或者read()和write();
7、关闭网络连接;

UDP:
与之对应的UDP编程步骤要简单许多,分别如下:
UDP编程的服务器端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();
4、循环接收数据,用函数recvfrom();
5、关闭网络连接;

UDP编程的客户端一般步骤是:
1、创建一个socket,用函数socket();
2、设置socket属性,用函数setsockopt();* 可选
3、绑定IP地址、端口等信息到socket上,用函数bind();* 可选
4、设置对方的IP地址和端口等属性;
5、发送数据,用函数sendto();
6、关闭网络连接;

TCP和UDP是OSI模型中的运输层中的协议。TCP提供可靠的通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输。

UDP补充:
UDP不提供复杂的控制机制,利用IP提供面向无连接的通信服务。并且它是将应用程序发来的数据在收到的那一刻,立刻按照原样发送到网络上的一种机制。即使是出现网络拥堵的情况下,UDP也无法进行流量控制等避免网络拥塞的行为。此外,传输途中如果出现了丢包,UDO也不负责重发。甚至当出现包的到达顺序乱掉时也没有纠正的功能。如果需要这些细节控制,那么不得不交给由采用UDO的应用程序去处理。换句话说,UDP将部分控制转移到应用程序去处理,自己却只提供作为传输层协议的最基本功能。UDP有点类似于用户说什么听什么的机制,但是需要用户充分考虑好上层协议类型并制作相应的应用程序。

TCP补充:
TCP充分实现了数据传输时各种控制功能,可以进行丢包的重发控制,还可以对次序乱掉的分包进行顺序控制。而这些在UDP中都没有。此外,TCP作为一种面向有连接的协议,只有在确认通信对端存在时才会发送数据,从而可以控制通信流量的浪费。TCP通过检验和、序列号、确认应答、重发控制、连接管理以及窗口控制等机制实现可靠性传输。

TCP与UDP区别总结:
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保   证可靠交付
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

 


参考:
https://blog.csdn.net/Li_Ning_/article/details/52117463
https://blog.csdn.net/sinat_37138973/article/details/72822229

网络原理-计算机网络详解-传输层之UDP协议

数据单位

UDP 传送的数据单位协议是 UDP 报文或用户数据报


特点

UDP 是无连接的,即发送数据之前不需要建立连接

UDP 使用尽最大努力交付,即不保证可靠交付,同时也不使用拥塞控制

UDP 是面向报文的.UDP 没有拥塞控制,很适合多媒体通信的要求

UDP 支持一对一、一对多、多对一和多对多的交互通信

UDP 的首部开销小,只有 8 个字节


具体实现

发送方 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层.UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界

应用层交给 UDP 多长的报文,UDP 就照样发送,即一次发送一个报文

接收方 UDP 对 IP 层交上来的 UDP 用户数据报,在去除首部后就原封不动地交付上层的应用进程,一次交付一个完整的报文


要求

应用程序必须选择合适大小的报文


UDP首部格式

说明:

  • 户数据报 UDP 有两个字段:数据字段和首部字段.首部字段有 8 个字节,由 4 个字段组成,每个字段都是两个字节
  • 在计算检验和时,临时把“伪首部”和UDP用户数据报连接在一起,伪首部仅仅是为了计算检验和

图释:

首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。【也就是说伪首部不会添加到数据包里面】

抓包过后才发现,ip数据包首部没有添加可选项,就直接装载 udp数据了。


发送UDP请求的客户端图释

参考:

http://www.cnblogs.com/kzang/articles/2582879.html