运输层和网络层的关系、
- 运输层(TCP或UDP)为运行在不同主机上的进程之间提供逻辑通信
- 网络层(IP协议)提供了主机之间的逻辑通信
IP协议的服务模型、
尽最大努力交付服务。但它并不做任何确保:
1、 不确保报文段的交付
2、 不确保报文段的按序交付
3、 不确保报文段中数据的完整性
所以IP被称为不可靠服务。
UDP和TCP协议的服务模型、
将两个端系统间IP的交付服务扩展为运行在端系统上的两个进程之间的交付服务。这种服务被称为运输层的多路复用与多路分解。
UDP和TCP可以通过在其报文段首部中包括差错检查字段而提供完整性检查。进程到进程的数据交付和差错检查是两种最低限度的运输层服务,也是UDP所能提供的仅有的两种服务。
所以,与IP一样,UDP也是一种不可靠的服务,不能保证一个进程所发送的数据能够完整无缺地到达目的进程。
(听起来好像上面两句话有矛盾,提供完整性检查,为什么又说是不可靠的呢?其实不矛盾,完整性检查的对象是一个分组,一个报文段的完整性,而非一个进程发送的所有数据作为一个整体的完整性)
TCP为应用程序提供了几种附加服务:
1、提供可靠数据传输。通过使用流量控制、序号、确认和定时器来确保
2、提供拥塞控制
TCP提供更多服务,必然会比UDP复杂。
多路复用和多路分解、
考虑一个具体的场景,一台计算机正在运行4个进程:2个Telnet进程、一个FTP进程和一个HTTP进程。这台计算机的运输层从底层的网络层接收数据时,它需要将所接收到的数据定向到这4个进程中的一个。
一个进程会有一个或多个套接字,它相当于从网络向进程传递数据和从进程向网络传递数据的门户。由于在任一时刻,在接收主机上可能有不止一个套接字,所以每个套接字都会有唯一的标识符。(同时,标识符的格式取决于它是UDP还是TCP套接字)
所以,问题转换成接收主机怎样将一个到达的运输层报文段定向到适当的套接字。为了完成这个任务,每个运输层报文段中会有几个字段。在接收端,运输层检查这些字段,标识出接收套接字,进而将报文段定向到该套接字。
- 多路分解:将运输层报文段中的数据交付到正确的套接字的工作
- 多路复用:在源主机从不同套接字中收集数据块,并为每个数据块封装上首部信息(用于在以后分解)从而生成报文段,然后将报文段传递到网络层的工作
可以看出,分解和复用是两个相反的操作。
端口号、
套接字的标识符其实就是端口号。下面是一个传输层报文的端口字段。

端口号范围在0-65535。其中0-1023范围的端口号是周知端口号,是受限制的,它们保留给诸如HTTP(端口号80)和FTP(端口号21)之类的周知应用层协议来使用。
UDP的多路复用和多路分解、
如果应用程序开发者所编写的代码实现的是一个“周知协议”的服务器端,那么开发者就必须为其分配一个相应地周知端口号。通常,应用程序的客户端让运输层自动地(并且是透明地)分配端口号,而服务器端则分配一个特定的端口号。
一个UDP套接字由一个二元组来全面标识,该二元组包含一个目的IP地址和一个目的端口号。
因此,如果两个UDP报文段有不同的源IP地址和/或源端口号,但具有相同的目的IP地址和目的端口号,那么这两个报文段将通过相同的目的套接字被定向到相同的目的进程。
TCP的多路复用和多路分解、
在 TCP 中,已连接套接字和请求套接字是不同的概念。服务器端的监听套接字和已连接套接字都是服务器进程用于通信的套接字,它们是不同的套接字,不会被混淆或者产生竞争关系。监听套接字不会收到已连接套接字的报文,只能收到请求连接的报文。
当客户端使用 connect
函数向服务器端请求建立 TCP 连接时,系统会创建一个未连接套接字或者使用一个已经bind过的已命名套接字,这个套接字只能通过 connect
函数来指定远端地址和端口,并且只能用来建立连接。如果连接成功,系统会在客户端主机上创建一个新的已连接套接字,这个已连接套接字可以通过 read
和 write
等函数进行数据传输。
在连接建立成功后,返回的套接字描述符和原来的套接字描述符是同一个,也就是原来请求连接的套接字,只不过在建立连接后变成了已连接套接字。已连接套接字上的本地端口号和原来的套接字绑定的端口号是相同的。但是,由于已连接套接字上已经建立了连接,所以后续发送数据时不需要再指定目的端口号和地址了,因为已经通过连接建立过程中交换的信息获取到了远程主机的地址和端口号,操作系统会自动将数据发送到正确的套接字上。
当使用 bind
函数为套接字绑定本地地址后,系统会将该套接字标识为一个已命名套接字。如果你随后调用 connect
函数发起一个 TCP 连接,系统会将该已命名套接字转换为一个已连接套接字,并使用远程地址和端口号来标识该连接。因此,在你的情况下,如果你在调用 connect
函数之前已经调用了 bind
函数来为套接字绑定本地地址,那么系统将使用该已命名套接字创建 TCP 连接,而不会创建一个新的未连接套接字。
已连接套接字的本地和远端地址都已经确定了,因此在数据传输时不需要再次指定远端地址和端口号。已连接套接字也不能使用 connect
函数来更改远端地址和端口号。如果需要更改远端地址和端口号,需要使用 close
函数关闭已连接套接字,再创建新的未连接套接字来建立新的连接。
请求套接字和已连接套接字的区别在于,请求套接字只能用来建立连接,而已连接套接字可以进行数据传输,并且不能更改远端地址和端口号。已连接套接字是在连接建立成功后系统生成的,请求套接字则只是一个中间状态。
一个TCP套接字由一个四元组来标识。包含源IP地址,源端口号,目的IP地址,目的端口号。
因此,当一个TCP报文段从网络到达一台主机时,该主机使用全部4个值来将报文段定向(分解)到相应地套接字。
特别与UDP不同的是,具有不同源IP地址或源端口号,但具有相同目的IP地址或目的端口号的两个到达TCP报文段将被定向到两个不同的套接字;除非TCP报文段携带了初始创建连接的请求。
- 首先解释分号前一句。因为TCP是面向连接的,需要经过“三次握手”建立连接。服务器每收到一个客户进程的连接请求,都要建立一个新的连接——包括创建一个新的服务器进程与客户进程通信,与一个相应的套接字。
更具体地说,客户进程1与服务器的TCP连接,客户进程2与服务器的TCP连接是不同的两个TCP连接。客户进程1会与服务器进程1进行TCP连接,客户进程2会与服务器进程2进行TCP连接,这2个服务器进程也需要有2个不同的套接字。有n个客户进程就至少需要n个套接字。所以源不同,就会被定向到不同的套接字。 - 分号后一句。服务器进程在TCP连接中,会有一个“监听套接字”用于建立与客户进程之间的TCP连接。这个“监听套接字”是唯一的,仅在“三次握手”时会收到报文。所以如果当两个客户进程同时发出请求与服务器进程建立连接的报文段,它们会被定向到同一个套接字,即“监听套接字”。
事实上,当今高性能的Web服务器通常只使用一个进程,但是会为每个新的客户连接创建一个具有新连接套接字的新线程。
Comments NOTHING