摘要:

    本文简介了TCP面向连接理论知识,具体讲述了TCP报文各个字段含义。并从Wireshark俘获分组中选取TCP连接建立相关报文段进行分析。

一、概述

    TCP是面向连接的可靠传输协议,两个进程互发数据之前须要建立连接,这里的连接仅仅只是是端系统中分配的一些缓存和状态变量,中间的分组交换机不维护不论什么连接状态信息。

连接建立整个步骤例如以下(即三次握手协议):

首先,客户机发送一个特殊的TCP报文段;

其次,server用还有一个特殊的TCP报文段来响应;

最后,客户机再用第三个特殊报文段作为响应。

图1 三次握手协议示意图[1]

二、TCP报文格式

2.1 概述

为了提供可靠的传输数据,TCP报文首部字段有较多的字段。TCP报文格式例如以下图:

图2 TCP报文格式

源和目标port

    用于多路复用/多路分解来自或送至上层应用的数据。能够这样理解。port用来标识同一台计算机的不同进程。

序列号和确认号

    这两个字段是TCP可靠传输服务的关键部分,序列号是该报文段首字节的字节流编号(TCP把数据看成是有序的字节流,TCP隐式地对数据流的每一个字节进行编号)。这样理解可能更直观,当报文被分解成多个报文段时。序列号就是报文段首字节在整个报文的偏移量。确定号指定下一个期待的字节。TCP是全双工的,如果从主机A接收到主机B的数据,则主机A填充进报文段的确认号是主机A期望从主机B收到的下一个字节序号。

还没理清这两者的关系?见下图(三次握手):

图3 正常情况下TCP连接建立过程

首部长度(4位)

    由于选项是不定长的,这就须要标识整个首部字段的长度(单位是32位字),即5+选项个数。4位,单位是32位字,所以首部最长是15*4=60字节,即选项最长是40字节(10个选项)。

标志

URG

    指示报文段里存在着被发送方的上层实体标记为"紧急"数据,当URG=1时,其后的紧急指针指示紧急数据在当前数据段中的位置(相对于当前序列号的字节偏移量),TCP接收方必须通知上层实体。

ACK

    当ACK=0时,表示该数据段不包括确认信息。当ACK=1时。表示该报文段包括一个对已被成功接收报文段的确认。

PSH

    当PSH=1时。接收方在收到数据后马上将数据交给上层,而不是直到整个缓冲区满。

RST

    用于重置一个已经混乱的连接(如主崩溃),也可用于拒绝一个无效的数据段或者拒绝一个连接请求。一般而言,假设你得到的数据段被设置了RST位。那说明你这一端有问题了。

SYN

    用于建立连接过程,在连接请求中。SYN=1和ACK=0表示该数据段没有使用捎带的确认域,而连接应答捎带一个确认。即SYN=1和ACK=1

    注:捎带是指对客户机到server数据的确认被装载在一个承载server到客户机的数据报文段中。

FIN

    用于释放一个连接,表示发送方已经没有数据要传输了。

此时,接收方可能继续接收数据。好在SYN和FIN数据段都有序列号。从而保证了这两种数据段以正确顺序被处理。

窗体大小

    用于流控制(确保连接的不论什么一方都不会过快地发送过量的分组而淹没还有一方),窗体大小指定了从被确认的字节算起能够发送多少个字节。

校验和

    提供了额外可靠性。在计算检验和的时候,TCP的Checksum域设为0,假设数据域的字节数为奇数,则数据域填补一个额外的0字节。校验和算法:将全部的16位字按1的补码形式累加起来。取累加结果的补码。因此,当接收方运行相同计算时(包含Checksum域),结果应该是0。

紧急指针

    參考标志字段的URG位。

选项

    选项部分是为了适合复杂网络环境和更好地服务于应用层设计的。

TCP选项最长是40字节。详情见2.2。

数据

    无不论什么数据的TCP段也是合法的。通经常使用于确认和控制信息。

2.2 选项字段[2]

    TCP选项部分非常好出如今已经建立连接的会话中。仅仅要出如今TCP连接建立阶段,即三次握手。TCP选项部分实际运用有下面几种:

(1)最大报文传输段(MMS, Maximum Segment Size)

    用于发送发与接收方协商最大报文段长度(不过净荷数据,不包含TCP首部字段)。TCP在三次握手中,每一方都会通告期望收到的MSS(MSS只出如今SYN数据包中),假设一方不接受还有一方的MSS值,则使用默认的536字节净荷数据,即主机可以接受20+536字节的TCP报文段。

(2)窗体扩大选项(Window scaling)

    TCP报文的窗体大小字段占16位。即最大值是65535,但随着时延和带宽比較大的通信产生(如卫星通信),须要更大的窗体满足性能和吞吐率。这就是窗体扩大选项存在的意义。样例见參考资料[2]。

    Windows scaling占3个字节,最后一个字节是移位值(Shift count),即首部的窗体位数16向左移动,如移位值为14。则新的窗体最大值增大到65535*(2^14)。

    窗体扩大选项是在TCP建立之初进行协商,假设已实现了窗体扩大。当不再须要扩大窗体时。发送移位值=0就能够恢复到原窗体大小。即65535。

(3)选择确认选项(SACK, Selective Acknowledgements)

    考虑这样情况,主机A发送报文段12345,主机B收到135且报文无差错。SACK用来确保仅仅重传缺少的报文段,而不是重传全部报文段。

    SACK选项须要2个功能字节。一个用来指明使用SACK选项(SACK Permission),还有一指明这个选项占多少字节。

    那怎么形容丢失的报文段2。说明2的左右边界各自是1、3。TCP的数据报文是有字块边界的。而这样的边界是由序列号表示的。

    最多能指明多少个字节块的边界信息呢?答案是4个。这是由于选项字段最大是40字节,去除2个功能字节。序列号是32位即4字节,而且须要左右边界。所以(40-2)/8 = 4。

(4)时间戳选项(timestamps)

    时间戳选项用来计算往返时间RTT,发送方在发送报文段时把当前时钟的时间值放入时间戳字段,接收方将该时间戳字段的值拷贝到确认报文中,当接收方收到确认报文,对照确认报文的时间戳(等于发送方发送报文段的时间戳)和如今的时钟,就可以算出RTT。

    时间戳选项还可用于防止回绕序号PAWS。

序列号仅仅有32位,每2^32个序列号就会回绕(想想环形队列)。採用时间戳选项非常easy区分同样序列号的报文段。

(5)NOP(NO-Operation)

    TCP的头部必须是4字节的倍数,而大多数选项不是4字节倍数。不足的用NOP填充。

除此之外,NOP也用于切割不同的选项数据,如窗体扩大选项和SACK之间使用NOP隔离(以下的实例将看到这一点)。

三、实例解析

3.1 概述

    还是以訪问百度首页为例,首先用DNS协议将URL解析成IP地址,接着在客户机和server间建立TCP连接。用Wireshark俘获的分组例如以下图:

图4 Wireshark俘获建立TCP连接分组

    你一看会认为有些奇怪,理论上应该是3个分组的,怎么有6个分组?先不急。先把这6个报文收发示意图作出来(结合时间和报文含义),例如以下:

图5 TCP连接建立实例

    从图可知,连接建立伊始。客户机发了两个报文段。这或许是为了更快建立连接(如果有个请求报文段丢失。也不至于要等一段时间,重发报文)。接下来。以19、21、22(上图红色线条所看到的)分析TCP连接建立过程。

3.1 第一次握手19

Wireshark俘获TCP连接第一次握手的报文段例如以下:

图6 TCP连接第一次握手实例

这里主要挑几个字段分析:

    标志字段。SYN=1、ACK=0表示该数据段没有使用捎带的确认域。

    最大报文段长度(MMS)1460是怎么来的。链路层的以太网物理特性决定数据帧长度为1500(即MTU,最大传输单元),1460=1500-20(IP首部长度)-20(TCP首部长度)。不要被该报文首部长度32字节所迷惑,这仅仅是建立连接过程。MSS与MTU关系见下图[2]:

图7 MSS与MTU关系

    NOP字段。能够作为不足4倍数字节填充,也可作为选项间分隔,该报文段出现了3个NOP,详细功能见下图:

图8 TCP报文NOP字段

3.3 第二次握手21

    server响应clientTCP报文段,此时确认号为1了。SYN=1、ACK=1表明连接应答捎带一个确认,Wireshark俘获分组例如以下:

图9 TCP连接第二次握手实例

    为什么MSS是1452而不是1460?

这是由于使用PPPoE(Point-to-Point over Ethernet。能够使以太网的主机通过一个简单的桥接设备连到一个无端的接入集中器上[3])拨号上网。PPoP首部是8个字节,所以PPPoE的MTU是1492,MSS也就为1492-40=1452。

    那么,TCP连接建立后传输数据的MSS是多少呢,1460 or 1452 or 536 ?我的理解是默认值536,这样理解对吗?求指点!

3.4 第三次握手22

    客户机再次server的报文段,此时序列号和确认号都为1。没有选项字段,Wireshark俘获的分组信息例如以下:

图10 TCP连接第三次握手实例

    值得注意的。由于窗体扩展大小协商未果,所以就不扩大窗体了,即窗体大小最大为65535。

如此,TCP连接建立:-)

Linux网络编程--wireshark分析TCP包头的格式的更多相关文章

  1. Linux网络编程案例分析

    本代码来自于博主:辉夜星辰 本篇主要对运行代码中出现的问题进行分析,代码本身的内容后续展开讨论. 服务器端代码 /* Linux网络编程之TCP编程,服务器端读数据 socket函数之后,返回值ser ...

  2. Linux网络编程:基于TCP的程序开发回顾篇《转》

    面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你 ...

  3. 【深入浅出Linux网络编程】 “实践 -- TCP & UDP”

    通过上一篇博客的学习,你应该对基于epoll的事件触发机制有所掌握,并且通过阅读sio.c/sio.h应该也学会了如何封装epoll以及如何通过设计令epoll更加实用(用户回调,用户参数). 简单回 ...

  4. Linux网络编程——浅谈 TCP 三次握手和四次挥手

    一.tcp协议格式 二.三次握手 在 TCP/IP 协议中.TCP 协议提供可靠的连接服务,採用三次握手建立一个连接. 第一次握手:建立连接时,client发送 syn 包(tcp协议中syn位置1. ...

  5. Linux网络编程二、tcp连接API

    一.服务端 1.创建套接字: int socket(int domain, int type, int protocol); domain:指定协议族,通常选用AF_INET. type:指定sock ...

  6. Linux网络编程9——对TCP与UDP的简易封装2.0

    具体生成动态库的操作及使用该动态库的操作请参见上篇博文.以下仅仅列出改进版本的代码. 代码 my_socket.h #ifndef __MY_SOCKET_H__ #define __MY_SOCKE ...

  7. Linux网络编程8——对TCP与UDP的简易封装

    引言 每次使用socket通信,都会有很对相似的操作.本文,会对TCP与UDP通信做一简单封装,并生成动态库. 代码 my_socket.h #ifndef __MY_SOCKET_H__ #defi ...

  8. 【Linux 网络编程】常用TCP/IP网络编程函数

    (1)函数socket /**************************************************************** ** 功能:创建一个套接字用于通信 ** 参 ...

  9. Linux网络编程7——使用TCP实现双方聊天

    思路 主线程负责发送消息,另一线程负责接收消息.服务端和客户端均是如此. 注意 当A方close掉用于通信的socket端口后,该端口是不会立即关闭的.因为此时可能B方的信息还没send完.因此,此时 ...

随机推荐

  1. HTML DOM应用案例1

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. RobotFramework自动化测试框架-移动手机自动化测试Get Element Location关键字的使用

    Get Element Location关键字用来获取一个Element的Location位置,该关键字接收一个参数[ locator ] 示例1:使用Get Element Location来获取一 ...

  3. SpringBoot下配置FreeMarker配置远程模版

    需求产生原因 要求在同一个接口中,根据不同的参数,返回不同的视图结果 所有的视图中的数据基本一致 要求页面能静态化,优化SEO 例如:A接口返回客户的信息 客户A在调用接口时,返回其个性化定制的页面A ...

  4. Lombok 使用小结

    Lombok 简介 Lombok 是一种 Java 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO).它通过注释实现这一目的.通过在开发环境中实现 Lo ...

  5. 【LuaJIT版】从零开始在 macOS 上配置 Lua 开发环境

    前言 这篇文章针对的是基于 LuaJIT 的环境配置.借助于 LuaJIT,Lua 的执行效率可以进一步提升几十倍.如果你不是很清楚自己是需要 Lua 还是 LuaJIT,那么建议你从 LuaJIT ...

  6. this和static关键字

    this和static关键字 一.关键字this this表示对象自身的引用 this的作用 1.用来区别当前类对象的成员与参数成员 2.用来调用其它构造方法 构造方法: 1.每个类默认情况都有一个默 ...

  7. Error parsing HTTP request header Note: further occurrences of HTTP header parsing errors...java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are

    先将异常信息贴出: 该问题是tomcat进行http request解析的时候报的错,网上的解决办法主要是修改Tomcat的server.xml,在<Connector port="8 ...

  8. [转载] Redis-benchmark使用总结

    转载自http://blog.csdn.net/jiangguilong2000/article/details/24143721 Redis-benchmark为Redis性能测试工具. 指令说明: ...

  9. 《Linux命令行与shell脚本编程大全》第十章 使用编辑器

    主要介绍vim, nano, emacs,KWrite,Kate,GNOME 10.1 vim Unix系统最初的编辑器 10.1.1检查vim软件包 先搞明白你所用的Linux系统是哪种vim软件包 ...

  10. File I/O

    File I/O Introduction     We'll start our discussion of the UNIX System by describing the functions ...