TCP/IP 网络基础(三)传输层

网络层为通讯搭建好了基础架构,但对于应用程序来讲,它还是“不可用”的。相似地,即便各级铁路公路能通到全国的任何地方,但若是没有快递公司,你怎么寄东西?传输层就是给须要使用网络传输的应用程序直接使用的协议,也只有它提供了编程接口,即套接字。算法

传输层

TCP/IP在传输层的主要协议就是TCP和UDP。在这一层,它们引入了两个新的概念。编程

端口

网络层只有地址。但实际上,同一个地址(主机)上还有不一样的进程。为了区分这些进程就引入了端口。协议+IP+端口才能惟必定位到一个目标应用。
HTTP、FTP等上层协议使用的端口号都是固定的,这些叫作知名端口号,由0到1023占据。应用程序应该避免使用这些端口号。服务器

客户端/服务器

虽然通讯的两个实体应该是对等的,但必然有一个要先发出第一个请求,它就是客户端。另外一个就是服务器。而做为服务器,应该在第一个请求到来以前就启动并准备好,所以一般有个守护进程。也就是说,服务器监听一个或多个客户端的消息(TCP请求或UDP数据报),而客户端先开口说话。网络

UDP

即用户报文协议,它简单地封装了IP层的功能,提供无链接的通讯服务。UDP可能会出现丢包、乱序,也没法处理网络拥堵。而这些处理只能由使用它的上层应用实现。总而言之,UDP就是个轻量快速的协议,它每每应用于如下几个方面:架构

  • 包总量不多的通讯(如DNS,SNMP等)。
  • 音视频等对效率要求高而又对少许丢包不敏感的通讯。

TCP

TCP则是一种至关可靠的协议。它是面向链接的,而且有丢包重发,乱序整理,拥塞控制等功能。下面咱们来分别介绍它是怎么作的。socket

首先,首部校验和这个技术确定是有的。从物理层、数据链路层、网络层,甚至UDP都是具有的。只有它能防止内容出错。spa

链接管理

就是几乎家喻户晓的三次握手和四次挥手。上图:
3 way handshake3d

三次握手简单来讲就是客户端问服务端在吗?服务端回答我在,收到吱一声。客户端:吱。而后链接就创建了。固然中间有一些商量MTU(最大传输单元),同步发送和ACK序号的过程,略去不表。再看四次挥手:
4 way wavehand视频

四次挥手的过程至关于你和老板 1 on 1 结束时的场景。开始是大家你一句我一句,而后你对老板说:我没话了,你呢?老板:收到。可是我还有几件事要交代,bla bla... 最后,老板:好了我也说完了,你能够滚了。你:好的。blog

解决乱序和丢包

TCP为每段发送的数据都标上相对开头的字节偏移,接收端收到后则要响应一个ACK消息,告诉发送端本身收到了哪段数据。发送端发送了一段数据后迟迟没有收到确认消息,就会重发。而接收端反正有各个消息的序号,即便到达的数据乱序,也能正确地处理。若是收到重复的数据,就直接丢弃。这种技术就称为确认-重传机制。
图片描述

超时检测是经过定时器实现的,而定时器的时常不是固定的,而是根据估算的往返时间(RTT)动态调整。这也是TCP的NB之处。

滑动窗口

你觉得确认-重发机制就这么简单?真实的情形远比上图的复杂。TCP采用滑动窗口技术来实现其收发机制。
TCP链接的每一端都维护了一个接收窗口。它的意思就是所指望收到的下一段数据的序号范围。当数据到达时,序号超出这个窗口的都被丢弃。而后若是窗口的前几个字节已经收到了,就通知应用程序读取,再向后滑动窗口,而后发送ACK消息通知对端下一个期待的序号。
接收窗口

如上图,(A)表示但愿接收到的下一个字节序号是4,而且能够接受9个字节。(B)表示收到了4,5,6,7几个字节后,接收窗口向后移动了4个字节,而且发送的ACK将代表它接下来指望收到序号8.

同理,发送端也会维护一个发送窗口,而它又分为两部分:已发送但未收到确认的字节,和能够发送但未发送的字节。
发送窗口

如上图,字节1~3已经收到了确认消息。(A)表示当前的发送窗口。在字节4~7发送以后,被确认以前,发送窗口如(B)所示。此时,TCP还能够发送8~12而无须等待对方的ACK。但发送这些字节以后,定时器就会启动,若是超时以前尚未收到ACK,这段数据就会重发。
(C)表示字节4~7收到确认后发送窗口后移。

经过滑动窗口,能够解决简单的发送-应答机制每次只能发送一段数据,等待太多,效率过低的问题。如今的通讯情况以下:
图片描述

流控制和拥塞控制

流控制就是考虑接受端的接收能力,不要发的太快,否则接收不过来也是白白浪费网络流量。方法就是接收方把本身的接收窗口告诉发送方。

TCP采用慢启动,最终会趋向于占满带宽。具体算法再也不研究。

套接字

套接字即Socket Api,它起初发源于Unix,后来又被移植到Windows上成为Winsock。也就是说,六合以内,它是网络层编程的惟一接口。
本人目前没有直接对套接字编程的需求,在此只做简单介绍。

对服务器程序来讲,基本的操做是先得到socket结构体,接着调用bind绑定地址和端口,而后就监听在端口上。这个过程阻塞。当有链接进来时,程序继续,调用accept得到对方的socket,而后就能够调用recv和send进行通讯。

对客户端程序来讲,基本的操做是先得到socket结构体,再调用connect链接服务器,成功后调用recv和send进行通讯。

套接字API封装了前面讲解的滑动窗口等各类机制,对程序来讲,只能读取到数据流。由于TCP就是个流协议,没法控制数据段到达对端的方式。一样的,应用程序把数据发送给底层后,也没法控制数据如何被发送,如被打包仍是分拆。
所以,读取这种字节流时,若是是定长报文就很好办,每次读取固定字节便可。而若是报文内容是可变的,则每每采用这样一种方式:在每条报文前面加上一个首部,其中包含本记录的长度。这样接收端就能够分两次读取报文。第一次先用定长方式读取首部,取出长度,而后第二次读取所有报文。
record
这让我想起了之前似懂非懂地修改过的公司某产品的通讯协议…

TCP是万能的吗?

TCP彻底可靠,不须要应用程序考虑任何事情?固然没有这么神奇的事情。最简单地,若是两个端点通讯不可达,TCP就毫无办法。另外,应用程序是针对套接字编程,也要考虑对端的特殊输入、不友好动做等错误处理。具体可见《TCP/IP高效编程》的技巧9,11.

总结与感悟

网络协议不一样于咱们在一台机器上的编程约定和规范——后者老是至关可控的。举个极端的例子,你在 Word 程序里写了个你的银行密码,而后你不想再让第二我的知道。你能够删除这个字符串,或者删除文档,甚至在紧急状况下把电脑砸了。究其根源,是你从物理上拥有这台电脑。而网络协议,你把一个数据包发出去,而后事情就脱离了你的控制。剩下的任务就依赖于别的组织、我的、设备能正常尽职的工做,履行交付的承诺。这里面大量依赖了约定和信任。固然,任何一个不能遵照这些协议的公司的产品,也不可能有消费者会买单。想想,咱们每月付给运营商一些网费,就能够无限量地传输任何数据到任何地址,这不是一个神奇的事情吗?

相关文章
相关标签/搜索