推荐坪山网站建设,wordpress采用的mvc,哈尔滨建站的网站,微信5000人接推广费用一、TCP协议
1、TCP协议报文格式
TCP协议报文格式详解
2、TCP“三次握手”建立连接 位码即tcp标志位,有6种标示:
SYN(synchronous建立联机)
ACK(acknowledgement 确认)
PSH(push传送)
FIN(finish结束)
RST(reset重置)
URG(urgent紧急)
Sequence number(顺序号码)
Ac…一、TCP协议
1、TCP协议报文格式
TCP协议报文格式详解
2、TCP“三次握手”建立连接 位码即tcp标志位,有6种标示:
SYN(synchronous建立联机)
ACK(acknowledgement 确认)
PSH(push传送)
FIN(finish结束)
RST(reset重置)
URG(urgent紧急)
Sequence number(顺序号码)
Acknowledge number(确认号码)
1第一次握手主机Aclient与主机Bserver通信要建立一个TCP连接。首先B端先运行一个服务器进程发出一个“被动打开”命令给TCP。之后服务器进程不断探测端口看是否有客户端的连接请求。A端向TCP发送“主动打开”命令指名要与某个IP地址的某个端口建立TCP连接。第一次主机A向主机B发送连接请求报文。报文中指明了要链接的IP地址和端口号设置能够接受的TCP数据段最大值以及一些用户数据SYN1ACK0发送序号seqj.
2第二次握手A的连接请求到达B之后B的TCP查看是否有进程在侦听该端口如果没有就发送RST 1拒绝连接否则将到达的TCP数据段留给“侦听”进程进程将发回一个应答的TCP报文段其中SYN1ACK1,确认序号ack j1; 同时选一个自己的发送序号 : seq k 。
3第三次握手主机A收到B的确认之后再向B发送一个TCP报文段其中SYN1ACK1seqj1;ackk1; 就完成了三次握手。
状态分析
1第一次握手Client将标志位SYN置为1随机产生一个值seqJ并将该数据包发送给ServerClient进入SYN_SENT状态等待Server确认。
2第二次握手Server收到数据包后由标志位SYN1知道Client请求建立连接Server将标志位SYN和ACK都置为1ack (number )J1随机产生一个值seqK并将该数据包发送给Client以确认连接请求Server进入SYN_RCVD状态。
3第三次握手Client收到确认后检查ack是否为J1ACK是否为1如果正确则将标志位ACK置为1ackK1并将该数据包发送给ServerServer检查ack是否为K1ACK是否为1如果正确则连接建立成功Client和Server进入ESTABLISHED状态完成三次握手随后Client与Server之间可以开始传输数据了。
状态详解:
CLOSED 这个没什么好说的了表示初始状态。 LISTEN 这个也是非常容易理解的一个状态表示服务器端的某个SOCKET处于监听状态可以接受连接了。 SYN_RCVD 这个状态表示接受到了SYN报文在正常情况下这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态很短暂基本 上用netstat你是很难看到这种状态的除非你特意写了一个客户端测试程序故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态 时当收到客户端的ACK报文后它会进入到ESTABLISHED状态。 SYN_SENT 这个状态与SYN_RCVD遥想呼应当客户端SOCKET执行CONNECT连接时它首先发送SYN报文因此也随即它会进入到了SYN_SENT状态并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。 ESTABLISHED这个容易理解了表示连接已经建立了
相关知识 SYN攻击
在三次握手过程中Server发送SYN-ACK之后收到Client的ACK之前的TCP连接称为半连接half-open connect此时Server处于SYN_RCVD状态当收到ACK后Server转入ESTABLISHED状态。SYN攻击就是Client在短时间内伪造大量不存在的IP地址并向Server不断地发送SYN包Server回复确认包并等待Client的确认由于源地址是不存在的因此Server需要不断重发直至超时这些伪造的SYN包将长时间占用未连接队列导致正常的SYN请求因为队列满而被丢弃从而引起网络堵塞甚至系统瘫痪。SYN攻击时一种典型的DDOS攻击检测SYN攻击的方式非常简单即当Server上有大量半连接状态且源IP地址是随机的则可以断定遭到SYN攻击了使用如下命令可以让之现行 #netstat -nap | grep SYN_RECV
3、“四次挥手”断开连接
所谓四次挥手Four-Way Wavehand即终止TCP连接就是指断开一个TCP连接时需要客户端和服务端总共发送4个包以确认连接的断开。在socket编程中这一过程由客户端或服务端任一方执行close来触发整个流程如下图所示 由于TCP连接时全双工的因此每个方向都必须要单独进行关闭这一原则是当一方完成数据发送任务后发送一个FIN来终止这一方向的连接收到一个FIN只是意味着这一方向上没有数据流动了即不会再收到数据了但是在这个TCP连接上仍然能够发送数据直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭而另一方则执行被动关闭上图描述的即是如此。 1第一次挥手Client发送一个FIN用来关闭Client到Server的数据传送Client进入FIN_WAIT_1状态。 2第二次挥手Server收到FIN后发送一个ACK给Client确认序号为收到序号1与SYN相同一个FIN占用一个序号Server进入CLOSE_WAIT状态。 3第三次挥手Server发送一个FIN用来关闭Server到Client的数据传送Server进入LAST_ACK状态。 4第四次挥手Client收到FIN后Client进入TIME_WAIT状态接着发送一个ACK给Server确认序号为收到序号1Server进入CLOSED状态完成四次挥手
状态详解 FIN_WAIT_1 这个状态要好好解释一下其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别 是FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时它想主动关闭连接向对方发送了FIN报文此时该SOCKET即 进入到FIN_WAIT_1状态。而当对方回应ACK报文后则进入到FIN_WAIT_2状态当然在实际的正常情况下无论对方何种情况下都应该马 上回应ACK报文所以FIN_WAIT_1状态一般是比较难见到的而FIN_WAIT_2状态还有时常常可以用netstat看到。 FIN_WAIT_2上面已经详细解释了这种状态实际上FIN_WAIT_2状态下的SOCKET表示半连接也即有一方要求close连接但另外还告诉对方我暂时还有点数据需要传送给你稍后再关闭连接。 TIME_WAIT 表示收到了对方的FIN报文并发送出了ACK报文就等2MSL后即可回到CLOSED可用状态了。如果FIN_WAIT_1状态下收到了对方同时带FIN标志和ACK标志的报文时可以直接进入到TIME_WAIT状态而无须经过FIN_WAIT_2状态。 CLOSING 这种状态比较特殊实际情况中应该是很少见属于一种比较罕见的例外状态。正常情况下当你发送FIN报文后按理来说是应该先收到或同时收到对方的 ACK报文再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后并没有收到对方的ACK报文反而却也收到了对方的FIN报文。什 么情况下会出现此种情况呢其实细想一下也不难得出结论那就是如果双方几乎在同时close一个SOCKET的话那么就出现了双方同时发送FIN报 文的情况也即会出现CLOSING状态表示双方都正在关闭SOCKET连接。 CLOSE_WAIT 这种状态的含义其实是表示在等待关闭。怎么理解呢当对方close一个SOCKET后发送FIN报文给自己你系统毫无疑问地会回应一个ACK报文给对 方此时则进入到CLOSE_WAIT状态。接下来呢实际上你真正需要考虑的事情是察看你是否还有数据发送给对方如果没有的话那么你也就可以 close这个SOCKET发送FIN报文给对方也即关闭连接。所以你在CLOSE_WAIT状态下需要完成的事情是等待你去关闭连接。 LAST_ACK 这个状态还是比较容易好理解的它是被动关闭一方在发送FIN报文后最后等待对方的ACK报文。当收到ACK报文后也即可以进入到CLOSED可用状态了。
关于TIME_WAIT 状态更详细的可以参考我的另一篇博文
TIME_WAIT状态解析
4、TCP端口
TCP协议所涉及的端口是指用于面向连接或无连接的通信协议端口是网络通信进程的一种标识其属于一种抽象的软件结构属于软件端口范畴。在TCP协议中端口操作类似于一般的I/O操作进程获取一个端口相当于获取本地唯一的I/O文件可以用一般的读写式访问。详细解析请看我的另一篇博文
常见的网络端口
5、可靠传输
TCP可靠传输的工作原理 1.无差错 1无差错 A发送分组M1发送就暂停发送等待B的确认B收到M1就向A发送确认A收到对M1的确认后再发送下一个分组。若A收到连续的M1分组的确认信息则证明M2缺失 2出现差错A只要超过一段时间仍然没有收到确认就认为刚才发送的分组丢失了就重传前面发过的分组叫超时重传。由重传计时器实现。 而且
1A每次发送分组必须暂时保留分组副本
2分组和确认分组必须进行编号‘
3超时计时器的重传时间应当比数据在分组的平均往返时间更多一些。
3如果B收到重复的分组M1,不向上一层交付而且向A发送确认。
2.超时重传 其原理是在发送某一个数据以后就开启一个计时器在一定时间内如果没有得到发送的数据报的ACK报文那么就重新发送数据直到发送成功为止。
3.停止等待协议 优点是简单但是信道利用率太低了。解决方法是采用连续ARQ协议发送方维持发送窗口每次连续发送几个分组接收方采用累积确认对按序到达的最后一个分组发送确认。
缺点是不能向发送方反映出接收方已经正确收到的所有分组信息例如丢失中间的分组。
4.TCP可靠传输的实现
TCP 连接的每一端都必须设有两个窗口——一个发送窗口和一个接收窗口。TCP 的可靠传输机制用字节的序号进行控制。TCP 所有的确认都是基于序号而不是基于报文段。 发送过的数据未收到确认之前必须保留以便超时重传时使用。发送窗口不动(没收到确认)和前移(收到新的确认) 发送缓存用来暂时存放 发送应用程序传送给发送方 TCP 准备发送的数据TCP 已发送出但尚未收到确认的数据。接收缓存用来暂时存放按序到达的、但尚未被接收应用程序读取的数据 不按序到达的数据。 必须强调三点 1 A 的发送窗口并不总是和 B 的接收窗口一样大因为有一定的时间滞后。
2 TCP 标准没有规定对不按序到达的数据应如何处理。通常是先临时存放在接收窗口中等到字节流中所缺少的字节收到后再按序交付上层的应用进程。 3 TCP 要求接收方必须有累积确认的功能这样可以减小传输开销
5.滑动窗口图解 6、流量控制
流量控制方面主要有两个要点需要掌握。一是TCP利用滑动窗口实现流量控制的机制二是如何考虑流量控制中的传输效率。
流量控制 所谓流量控制主要是接收方传递信息给发送方使其不要发送数据太快是一种端到端的控制。主要的方式就是返回的ACK中会包含自己的接收窗口的大小并且利用大小来控制发送方的数据发送 这里面涉及到一种情况如果B已经告诉A自己的缓冲区已满于是A停止发送数据等待一段时间后B的缓冲区出现了富余于是给A发送报文告诉A我的rwnd大小为400但是这个报文不幸丢失了于是就出现A等待B的通知||B等待A发送数据的死锁状态。为了处理这种问题TCP引入了持续计时器Persistence timer当A收到对方的零窗口通知时就启用该计时器时间到则发送一个1字节的探测报文对方会在此时回应自身的接收窗口大小如果结果仍未0则重设持续计时器继续等待。传递效率 一个显而易见的问题是单个发送字节单个确认和窗口有一个空余即通知发送方发送一个字节无疑增加了网络中的许多不必要的报文请想想为了一个字节数据而添加的40字节头部吧所以我们的原则是尽可能一次多发送几个字节或者窗口空余较多的时候通知发送方一次发送多个字节。对于前者我们广泛使用Nagle算法即 *1. 若发送应用进程要把发送的数据逐个字节地送到TCP的发送缓存则发送方就把第一个数据字节先发送出去把后面的字节先缓存起来 *2. 当发送方收到第一个字节的确认后也得到了网络情况和对方的接收窗口大小再把缓冲区的剩余字节组成合适大小的报文发送出去 *3. 当到达的数据已达到发送窗口大小的一半或以达到报文段的最大长度时就立即发送一个报文段 对于后者我们往往的做法是让接收方等待一段时间或者接收方获得足够的空间容纳一个报文段或者等到接受缓存有一半空闲的时候再通知发送方发送数据。
7、拥塞控制
网络中的链路容量和交换结点中的缓存和处理机都有着工作的极限当网络的需求超过它们的工作极限时就出现了拥塞。拥塞控制就是防止过多的数据注入到网络中这样可以使网络中的路由器或链路不致过载。常用的方法就是 1. 慢开始、拥塞控制 2. 快重传、快恢复 一切的基础还是慢开始这种方法的思路是这样的 1. 发送方维持一个叫做“拥塞窗口”的变量该变量和接收端口共同决定了发送者的发送窗口 2. 当主机开始发送数据时避免一下子将大量字节注入到网络造成或者增加拥塞选择发送一个1字节的试探报文 3. 当收到第一个字节的数据的确认后就发送2个字节的报文 4. 若再次收到2个字节的确认则发送4个字节依次递增2的指数级 5. 最后会达到一个提前预设的“慢开始门限”比如24即一次发送了24个分组此时遵循下面的条件判定 *1. cwnd ssthresh 继续使用慢开始算法 *2. cwnd ssthresh停止使用慢开始算法改用拥塞避免算法 *3. cwnd ssthresh既可以使用慢开始算法也可以使用拥塞避免算法 6. 所谓拥塞避免算法就是每经过一个往返时间RTT就把发送方的拥塞窗口1即让拥塞窗口缓慢地增大按照线性规律增长 7. 当出现网络拥塞比如丢包时将慢开始门限设为原先的一半然后将cwnd设为1执行慢开始算法较低的起点指数级增长
上述方法的目的是在拥塞发生时循序减少主机发送到网络中的分组数使得发生拥塞的路由器有足够的时间把队列中积压的分组处理完毕。慢开始和拥塞控制算法常常作为一个整体使用而快重传和快恢复则是为了减少因为拥塞导致的数据包丢失带来的重传时间从而避免传递无用的数据到网络。快重传的机制是
1. 接收方建立这样的机制如果一个包丢失则对后续的包继续发送针对该包的重传请求 2. 一旦发送方接收到三个一样的确认就知道该包之后出现了错误立刻重传该包 3. 此时发送方开始执行“快恢复”算法 *1. 慢开始门限减半 *2. cwnd设为慢开始门限减半后的数值 *3. 执行拥塞避免算法高起点线性增长 二、UDP协议
1、定义
用户数据报协议是一种无连接的传输层协议提供面向事务的不可靠信息传送服务。UDP协议基本上是IP协议与上层协议的接口适用于端口分别运行在同一台设备上的多个应用程序。
2、特点
1无连接发送数据之前不需要建立连接。开销和发送之前的时间延迟较短。
2尽最大努力交付。可以采取一定策略实现可靠传输
3面向报文UDP对应用程序交付的报文添加UDP首部后直接交给IP层。不合并不拆分。
4没有拥塞控制网络拥塞不会使源主机发送率降低。
5UDP支持一对一一对多多对一的交互通信
6UDP首部开销较小8字节TCP为20字节、IP为20字节
3、数据报格式 用户数据报UDP有两个字段数据字段和首部字段。 首部字段很简单只有8个字节由4个字段组成每个字段的长度都是两个字节。
各字段的意义如下 1.源端口 源端口号在需要对方回信的时候选用不需要的时候可用全0
2.目的端口 目的端口号这在终点交付报文时必须要使用到。
3.长度 UDP用户数据报的长度(首部字段和数据字段)其最小值是8也即是只有首部。
4.检验和 在进行检验和计算时会添加一个伪首部一起进行运算。伪首部占用12个字节为4个字节的源IP地址、4个字节的目的IP地址、1个字节的0、一个字节的数字17、以及占用2个字节UDP长度。这个伪首部不是报文的真正首部只是引入为了计算校验和。相对于IP协议的只计算首部UDP检验和会把首部和数据一起进行校验。接收端进行的校验和与UDP报文中的校验和相与如果无差错应该全为1。如果有误则将报文丢弃或者发给应用层、并附上差错警告。
三、TCP协议与UDP协议的区别
TCPTransmission Control Protocol可靠的、面向连接的协议eg:打电话、传输效率低全双工通信发送缓存接收缓存、面向字节流。使用TCP的应用Web浏览器电子邮件、文件传输程序。
UDPUser Datagram Protocol不可靠的、无连接的服务传输效率高发送前时延小一对一、一对多、多对一、多对多、面向报文尽最大努力服务无拥塞控制。使用UDP的应用域名系统 (DNS)视频流IP语音(VoIP)。 常见的问题
问题1什么是面向连接、面向无连接 面向连接举例两个人之间通过电话进行通信。 面向无连接举例邮政服务用户把信函放在邮件中期待邮政处理流程来传递邮政包裹。显然不可达代表不可靠。 从程序实现的角度解析面向连接、面向无连接如下TCP面向连接UDP面向无连接在默认的阻塞模式下
在TCP协议中当客户端退出程序或断开连接时TCP协议的recv函数会立即返回不再阻塞因为服务端自己知道客户端已经退出或断开连接证明它是面向连接的而在UDP协议中recvfrom这个接收函数将会始终保持阻塞因为服务端自己不知道客户端已经退出或断开连接证明它是面向无连接的。 从上图也能清晰的看出TCP通信需要服务器端侦听listen、接收客户端连接请求accept等待客户端connect建立连接后才能进行数据包的收发recv/send工作。
而UDP则服务器和客户端的概念不明显服务器端即接收端需要绑定端口等待客户端的数据的到来。后续便可以进行数据的收发recvfrom/sendto工作。
问题2什么是面向字节流、面向报文
面向字节流虽然应用程序和TCP的交互是一次一个数据块大小不等但TCP把应用程序看成是一连串的无结构的字节流。TCP有一个缓冲当应用程序传送的数据块太长TCP就可以把它划分短一些再传送。如果应用程序一次只发送一个字节TCP也可以等待积累有足够多的字节后再构成报文段发送出去。
面向报文面向报文的传输方式是应用层交给UDP多长的报文UDP就照样发送即一次发送一个报文。因此应用程序必须选择合适大小的报文。若报文太长则IP层需要分片降低效率。若太短会是IP太小。谢希仁第五版。UDP对应用层交下来的报文既不合并也不拆分而是保留这些报文的边界。这也就是说应用层交给UDP多长的报文UDP就照样发送即一次发送一个报文。
问题3在默认的阻塞模式下为什么说TCP无边界UDP有边界
对于TCP协议客户端连续发送数据只要服务端的这个函数的缓冲区足够大会一次性接收过来即客户端是分好几次发过来是有边界的而服务端却一次性接收过来所以证明是无边界的
而对于UDP协议客户端连续发送数据即使服务端的这个函数的缓冲区足够大也只会一次一次的接收发送多少次接收多少次即客户端分几次发送过来服务端就必须按几次接收从而证明这种UDP的通讯模式是有边界的。
问题4UDP 如何发送大量的数据如何处理分包
用 updclient 一次不能发送太大的数据量不然就会报错一个在数据报套接字上发送的消息大于内部消息缓冲器或其他一些网络限制或该用户用于接收数据报的缓冲器比数据报小。但不知道一次到底能发多少字节如果把一个大的字节数组拆分成若干个字节数组发送那么接收时如何判断和处理呢
答方法很简单
1、在客户端将你要发送的内容文件什么的都可以分块每块内容进行编号然后发送
2、服务端在接收到你的分块数据以后根据你的客户端数据内容的编号重新组装
3、一般我们在发送数据的时候尽量采用比较小的数据块的方式我的都没有超过1024的数据块太大的话容易出现发送和接收的数据时间长匹配出问题。
问题5.UDP发包的问题
问udp发送两次数据第一次 100字节第二次200字节接包方一次recvfrom( 1000 ),收到是 100还是200还是300
答UDP是数据报文协议是以数据包方式所以每次可以接收100200在理想情况下第一次是无论recvfrom多少都是接收到100。当然可能由于网络原因第二个包先到的话有可能是200了。对可能会由于网络原因乱序所以可能先收到200所以自定义的udp协议包头里都要加上一个序列号标识发送与收包对应。
问题6.TCP的发包问题
问同样如果换成tcp,第一次发送 100字节第二次发送200字节recv( 1000 )会接收到多少
答tcp是流协议所以recv( 1000 )会收到300 tcp自己处理好了重传保证数据包的完整性
问题7.有分片的情况下如下处理
问如果MTU是1500使用UDP发送 2000那么recvfrom(2000)是收到1500还是2000?
答还是接收2000数据分片由ip层处理了放到udp还是一个完整的包。接收到的包是由路由路径上最少的MTU来分片注意转到UDP已经在是组装好的(组装出错的包会经crc校验出错而丢弃)是一个完整的数据包。
问题8.分片后的处理
问如果500那个片丢了怎么办udp又没有重传
答udp里有个crc检验如果包不完整就会丢弃也不会通知是否接收成功所以UDP是不可靠的传输协议而且TCP不存在这个问题有自己的重传机制。在内网来说UDP基本不会有丢包可靠性还是有保障。当然如果是要求有时序性和高可靠性还是走TCP不然就要自己提供重传和乱序处理( UDP内网发包处理量可以达 7M~10M/s )
问题9.不同连接到同一个端口的包处理
问TCP A - C发100 B - C发200 AB同时同一端口 C recv(1000) ,会收到多少 答A与C是一个tcp连接B与C又是另一个tcp连接所以不同socket所以分开处理。每个socket有自己的接收缓冲和发送缓冲
问题10.什么是TCP粘包
在应用开发过程中基于TCP网络传输的应用程序有时会出现粘包现象即发送方发送的若干包数据到接收方接收时粘成一包。详细解释如下由于TCP是流协议对于一个socket的包如发送 10AAAAABBBBB两次由于网络原因第一次又分成两次发送 10AAAAAB和BBBB如果接包的时候先读取10(包长度)再读入后续数据当接收得快发送的慢时就会出现先接收了 10AAAAAB,会解释错误 ,再接到BBBB10AAAAABBBBB也解释错误的情况。这就是TCP的粘包。
在网络传输应用中通常需要在网络协议之上再自定义一个协议封装一下简单做法就是在要发送的数据前面再加一个自定义的包头包头中可以包含数据长度和其它一些信息接收的时候先收包头再根据包头中描述的数据长度来接收后面的数据。详细做法是先接收包头在包头里指定包体长度来接收。设置包头包尾的检查位如群空间0x2开头0x3结束来检查一个包是否完整。对于TCP来说1不存在丢包错包所以不会出现数据出错 2如果包头检测错误即为非法或者请求直接重置即可
为了避免粘包现象可采取以下几种措施 一是对于发送方引起的粘包现象用户可通过编程设置来避免TCP提供了强制数据立即传送的操作指令pushTCP软件收到该操作指令后就立即将本段数据发送出去而不必等待发送缓冲区满 二是对于接收方引起的粘包则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施使其及时接收数据从而尽量避免出现粘包现象 三是由接收方控制将一包数据按结构字段人为控制分多次接收然后合并通过这种手段来避免粘包。