1. TCP面向连接的协议,是一个字节流协议,没有任何记录边界。发送的是数据分组。
2. TCP提供了可靠性:确认重传和重组
(1) TCP每发送一份数据都会要求对端进行确认。如果超时,就会重传。TCP会估计往返时间RTT,以确定等待多长时间重传。
(2) 如果多次发送数据分组,TCP可以保证分组的按序达到。即会根据序列号进行重组。
3. TCP提供流量控制
TCP在任何时刻通知对端,它此时一次能够接受多少字节的数据,即通告窗口。该窗口指出接受缓冲区当前可用的空间。
4. 为何说TCP是面向连接的?
因为其开始阶段有一个三次握手的过程,且连接之后,服务器端和客户端都会维持一个相同的套接字对,而连接之后,双方就通过对这个套接字对进行通信。
提供无连接的不可靠的服务。发送的是数据报。
没有可靠性机制,没有流量控制。
1. 首先服务端要socket,bind,listen,然后accept阻塞,等待客户端的连接。
2. 客户端socket,调用connect进行主动连接,发送SYN分组。占一个字节。
3. 服务器端接受到SYN分组后,进行ACK确认并捎带自己的SYN分组。占一个字节。
4. 当客户端接受到服务器端的确认ACK后,connect立即返回。然后向服务器端发送ACK确认。
5. 服务器端接受到这个ACK确认后,完成三次握手。
(1) 注意:这里为何服务器端在接受第三次ACK后,可能不立即返回accept?
因为内核为accept设置了两个缓存队列:未连接队列和已连接队列。
当一个SYN来到之后,首先放入未连接队列中,然后当其如果完成了三次握手(即最后一个ACK达到服务器端),则就放入已连接队列中,然后进程调用accept,
内核就从已完成队列队首项返回给进程,accept返回。
详见“4. 基于TCP套接字编程 ”中的“内核是如何进行连接排队的?”
(2) 注意这里SYN的作用是?
SYN的作用:连接的开始。通知对方自己的序列号,以便对以后的重传和重组提供序列号。
一般SYN还含有很多TCP选项:MSS—本端的最大分组大小;窗口规模(即窗口总大小);时间戳等。
1. 客户端调用close关闭连接,则客户端发送FIN分组。注意:发送FIN分组的意思是本端不会再发送任何数据。
2. 服务端接受这个FIN,然后read函数返回0,并发送对端一个ACK确认。
注意:此时服务器端仍然客户端发送数据是可能的。此时称为半关闭状态。
3. 当服务器端在某个时刻判断read返回0,之后它主动调用close函数进行关闭连接。发送FIN。
注意:此时是程序自己调用close,会发送FIN。当Unix某个进程终止时,它就会关闭其打开的描述符,也会发送FIN。
4. 客户端接受这个FIN,然后发送ACK返回。
注意:可以看出无论是客户端还是服务器端都是可以主动首先关闭的。
这个图很有意思,仔细看
从上图可知,当客户端接受到服务器端的FIN之后,就会变成TIME_WAIT状态。
该端点停留在这个状态的持续时间是MSL(最长分组生命期)的两倍。有时称2MSL。
1. 为何该端点要维护这个状态?
(1) 可靠地实现TCP全双工连接的终止
上图中假如客户端的发送最终一个ACK丢失,则服务器端会重传上一个FIN,则客户端需要保留状态来处理这个重传的FIN。
(2) 允许老的重复分节在网络中消逝。
假设TCP不维护这个状态,则某个客户端发送最终一个ACK后即结束。如果此时又有重新启动相同IP和端口客户端,则这个新的客户端可能会收到来自服务器端的老的信息(如上述的服务器重传FIN)。造成错误。
而此时TCP维护了这个状态后,TCP就有了一个机制,不会为具有TIME_WAIT状态的连接重新发起新的连接。这就会让老的分组在网络中自动消逝,这也是为何端点维持此状态的时间为2MSL。
任何时候,TCP/UDP/SCTP都使用16位的整数的端口号。即2个字节的整数。一般是short类型。
端口号分为三类:
众所周知的端口号0~1023。这些端口号一般都有特殊的含义。例如一般80都是web端口。
已登记的端口号1024~49151.这些端口可供用户程序中使用。
动态或私用端口号49152~65535.这些端口也就是临时端口,即如果用户没有指定端口,内核自动给程序分配的临时端口号。
一个TCP连接对应着一个套接字对:本地IP,本地端口号,对端IP,对端端口号。
一般服务器需要监听套接字对和已连接套接字对。
例如,某服务器bind的端口号为13,地址为INADDR_ANY,则监听套接字对为{*: 13 , * : *}。
当一个客户端connect之后,则监听套接字对中的本地IP就会被内核选取一个本地IP地址赋值,然后对端套接字就会从内核通过对方的连接信息得到。例如:
{192.2.3.2 : 13 , 150.2.6.54 : 8265}
这时我们应该维护监听套接字对,以用来监听其他的连接。所以server一般需要两个套接字描述符。而client一般需要一个套接字描述符。
注意:当并行服务器时,TCP用套接字对来标识客户端来的信息应该分配为谁。
每一个TCP套接字都有一个发送缓冲区,应用程序调用write函数时,内核就把应用程序的缓冲区数据全部复制到发送缓冲区。如果成功,write立即返回。如果套接字发送缓冲区容不下应用程序的缓冲区数据(或者应用程序缓冲区过大,或者套接字发送缓冲区已有其他数据),则write函数会被阻塞(如果该套接字是阻塞的)。
直到应用程序的缓冲区的全部数据复制到套接字发送缓冲区才被唤醒。
1. write函数也可能会被阻塞
2. write函数成功返回,只是代表数据被复制到发送缓冲区,并不代表对端已经接收到。
3. 内核会把套接字发送缓冲区的数据发送给对端,这时并不会删除缓冲区的数据(以便重传),只有对端的ACK来到之后,缓冲区才会把已确认的数据丢掉。
原文地址:http://blog.csdn.net/u013696062/article/details/45913545