它建立在网际层协议(IP)提供的数据包传输技术之上,。TCP使应用程序可使用连续的数据进行通信。除非由于网络故障导致连接中断或冻结,TCP都能保证数据流完好地传输。而不会发生丢包 ,重包或是乱序的问题。
1 TCP工作原理
如果使用udp提供的数据报机制,代码还要考虑传输的可靠性问题,以及错误是的恢复方案。但如果用TCP,数据包就隐藏在协议层之下,应用只需要型目标机器发生数据流,TCP会自动将丢失的信息重发,保证信息能够成功到达目标机器。对于程序可见的只有数据流,实际的数据包和序列号都被操作系统的网络栈巧妙地隐藏了。
如何提供可靠的连接:
#每个TCP数据包都有一个序列号
#并不使用顺序的整数作为数据包的序列号
#初始序列号是随机的
#并不通过锁步的方式通信,这种方式必须等待每个接收完才发下一个。相反,TCP可以无需等待一口气发多个。某一刻对方希望同时传输的数据量叫做TCP窗口的大小。
#接收方的TCP实现可以通过控制发送方的窗口大小来减缓或暂停。这叫流量控制。
#如果TCP认为数据包被丢弃,他会认为网络变拥挤,然后减少发送的数据量。
2 何时使用TCP
两台主机间建立TCP连接需要三个数据包:
SYN:“我想通信,这是数据包的初始序列号”
SYN-ACK:“好的,这是我向你发送数据包的初始序列号”
ACK::“好的”
通信结束时,要发送另外3个或4个数据包来关闭连接。
不需要使用TCP:
一。如果客户端只需向服务器发送单个较小的请求,并且请求后无需后续通信。
二。客户端与服务器之间不存在长时间的连接的情况下。
三。当丢包现象发生时,如果应用程序有比简单地重传数据聪明的多的方法的话。
3 TCP套接字的含义
getsockname()函数用于获取一个套接字的名字。它用于一个已捆绑或已连接套接字s,本地地址将被返回。本调用特别适用于如下情况:未调用bind()就调用了connect(),这时唯有getsockname()调用可以获知系统内定的本地地址。在返回时,namelen参数包含了名字的实际字节数。
跟UDP的情况一样,TCP也使用端口号来区分同一IP地址上运行的不同应用程序。对于知名端口号和临时端口号的划分习惯于UDP是一致的。
9 小结
基于TCP的“流”套接字提供了所有必须的功能,包括重传丢失数据包,重新排列接收到的顺序错误的数据包,以及将大型数据流分割为针对特定网络的具有最优大小的数据包。这些功能提供了对网络上两个套接字之间传输并接收数据流的支持。
更udp一样,TCP也使用端口号来区分同一机器上可能存在的多个流端点。想要接收TCP连接请求的程序需要通过bind()绑定到一个端口,在套接字上运行listen(),然后进入一个循环,不断运行accept(),为每个连接请求新建一个套接字(用于与特定客户端进行通信)。如果程序想要连接到已经存在的服务器端口,那么只需要建一个套接字,然后调用connect()连接到一个地址即可。
服务器通常都要为绑定的套接字设置SO_REUSEADDR选项,以防止同一端口上最近运行的正在关闭中的连接阻止操作系统进行绑定。
实际上,数据是通过send()和recv()来发送和接收的。一些基于TCP的协议会对数据进行标记,这样客户端和服务器就能自动得知通信何时完成。其他协议把TCP套接字看作真正的流,会不断发射接收数据,直到文件传输结束。套接字shutdown()可以用来为套接字生成一个方向上的文件结束符(所以套接字本质上都是双向的),同时保持另一方向的连接处于打开状态。
如果通信双方都写数据,套接字缓冲区被越来越多的数据填满,二这些数据去从没被读取,那么就可能发生死锁。最终在某个方先上再也无法通过send()来发数据,然后可能会永远等待缓冲区清空,从而导致阻塞。
如果想把一个套接字传递给一个支持读取或写入普通文件对象的 Python模块,可以使用makefile()方法。该方法返回一个Python对象。调用方法需要读取及写入数据时,该对象会在底层调用recv()he send().