前言

本文旨在通过形象的例子和实操,把无形的、虚拟的网络转为具体的、可视化的。带领网络小白一步步的掌握 TCP 三次握手核心知识点,为后续深入学习 TCP 协议打基础。

通俗版

如下图所示,小明(客户端)给小美(服务端)打电话,在经过互相询问和应答,确认通信畅通后,才开始愉快地聊天。(本例子不一定无懈可击主要是意会即可)

细节版

一个 TCP 报文段分为首部和数据两部分,TCP 所有的功能都体现在首部的各个字段中。

序列号:本报文段所发送数据的第一个字节的序号,在建立连接时会随机生成初始序列号 ISN(Inital Sequence Number)。

确认号:下一次应该收到的数据的序列号,若确认号为 N,则代表到序列号 N-1 为止的数据都已经正确收到。

控制位:

  • ACK:为 1 时确认号才生效,在建立连接后所有传送的报文段 ACK 均为 1。

  • SYN:为 1 时表示这是连接请求(SYN=1,ACK=0)或者连接接受(SYN=1,ACK=1)报文。

由于上述报文都未携带数据,即 len=0,所以响应的 ack 等于请求的 seq+1。

实战版

为了抓到比较纯净的包,我们实现一个简单的 TCP Server,接受客户端的请求并回复。

func main() {
// 监听端口
l, err := net.Listen("tcp", "0.0.0.0:8080")
if err != nil {
panic(err)
}
defer l.Close() for {
// 接受连接
conn, err := l.Accept()
if err != nil {
log.Printf("accept err: %s\n", err)
continue
}
go hello(conn)
}
} func hello(conn net.Conn) {
defer conn.Close()
buf := make([]byte, 1024)
// 读数据
if _, err := conn.Read(buf); err != nil {
log.Printf("conn read err: %s\n", err)
return
}
log.Printf("%s\n", string(buf)) // 写数据
if _, err := conn.Write([]byte("hello, xiao ming.\n")); err != nil {
log.Printf("conn write err: %s\n", err)
return
}
}

客户端请求:

echo -n "hello, xiao mei." | nc 81.68.197.93 8080

使用 wireshark 分析(统计 - 流量图)可以清楚的看到三次握手的过程。

同时也能看到 seq 和 ack 的关系,在握手成功后发送了 len=16 的包后,然后 ack=17 表示序列号在 16 之前的数据都已经正确收到。

注意:ISN 是一个随机数,并不为 0,wrieshark 为了显示更友好,使用了相对序号,在鼠标右键选项中取消即可看到真正的序列号,如:Seq=3503481500。

握手包源文件下载地址

状态机

TCP 所谓的面向连接本质就是客户端和服务端的数据结构都各自维护了一个”连接状态“,三次握手期间状态变化如下:

LISTEN:服务端主动监听一个端口,等待客户端的连接请求

SYN-SENT:发送 SYN 包后的状态

SYN-RECEIVED:收到 SYN 包,且发送了 SYN+ACK 包后的状态

ESTABLISHED:连接建立成功

# 使用 netstat 命令查看当前系统的 TCP 连接状态
$ netstat -t
Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 ubuntu:58824 39.156.66.18:http TIME_WAIT
tcp 0 0 localhost:20172 localhost:37276 ESTABLISHED

参考

图解TCP/IP(第5版)

计算机网络(第7版)谢希仁

酷壳 - TCP 的那些事儿(上)

循序渐进搞懂 TCP 三次握手核心的更多相关文章

  1. 一文彻底搞懂 TCP三次握手、四次挥手过程及原理

    原创文章出自公众号:「码农富哥」,欢迎收藏和关注,如转载请注明出处! TCP 协议简述 TCP 提供面向有连接的通信传输,面向有连接是指在传送数据之前必须先建立连接,数据传送完成后要释放连接. 无论哪 ...

  2. 小白都能看懂的tcp三次握手

    众所周知,TCP在建立连接时需要经过三次握手.许多初学者经常对这个过程感到混乱:SYN是干什么的,怎么一会儿是1一会儿是0?怎么既有大写的ACK又有小写的ack?为什么ACK在第二次握手才开始出现?初 ...

  3. 阿里二面,面试官居然把 TCP 三次握手问的这么细致

    TCP 的三次握手和四次挥手,可以说是老生常谈的经典问题了,通常也作为各大公司常见的面试考题,具有一定的水平区分度.看似是简单的面试问题,如果你的回答不符合面试官期待的水准,有可能就直接凉凉了. 本文 ...

  4. TCP三次握手原理,你真的了解吗?

    最近碰到一个问题,Client 端连接服务器总是抛异常.在反复定位分析.并查阅各种资料搞懂后,我发现并没有文章能把这两个队列以及怎么观察他们的指标说清楚. 问题描述 场景:Java 的 Client ...

  5. TCP 三次握手原理,你真的理解吗?

    最近,阿里中间件小哥哥蛰剑碰到一个问题——client端连接服务器总是抛异常.在反复定位分析.并查阅各种资料文章搞懂后,他发现没有文章把这两个队列以及怎么观察他们的指标说清楚. 因此,蛰剑写下这篇文章 ...

  6. Wireshark基本介绍和学习TCP三次握手

    wireshark介绍 wireshark的官方下载网站: http://www.wireshark.org/ wireshark是非常流行的网络封包分析软件,功能十分强大.可以截取各种网络封包,显示 ...

  7. iOS 开发:TCP三次握手连接

    在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接. 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认: 第二次握 ...

  8. TCP三次握手四次挥手详解

    转载 http://www.cnblogs.com/zmlctt/p/3690998.html 相对于SOCKET开发者,TCP创建过程和链接折除过程是由TCP/IP协议栈自动创建的.因此开发者并不需 ...

  9. TCP三次握手及四次挥手详细 转

    一.TCP报文格式        TCP/IP协议的详细信息参看<TCP/IP协议详解>三卷本.下面是TCP报文格式图: 图1 TCP报文格式 上图中有几个字段需要重点介绍下:      ...

随机推荐

  1. 二进制部署1.23.4版本k8s集群-6-部署Node节点服务

    本例中Master节点和Node节点部署在同一台主机上. 1 部署kubelet 1.1 集群规划 主机名 角色 IP CFZX55-21.host.com kubelet 10.211.55.21 ...

  2. Nginx解决跨域问题No 'Access-Control-Allow-Origin'

    使用nginx在server块下的location块下为请求添加请求头来解决跨域 add_header 'Access-Control-Allow-Origin' '*'; add_header 'A ...

  3. LGP5664题解

    厉害. 对于每一列选的数最多占一半,我们得设计一个三维 DP.然而状态刚好够,但是转移明显炸了(而且似乎还需要多项式?) 考虑正难则反,DP 不合法的方案数.总方案数很好算. 发现不合法的方案数只有某 ...

  4. jsp安全问题及其解决建议

    jsp编程语言自从推出之日起,由于它的快速.平台无关.可扩展.面向对象等特性得到了越来越广泛的应用,越来越多的厂家开发出了各种各样的支持平台如IBM 公司的WebSphere.BEA公司的WebLog ...

  5. DataStage中Transformer的函数大全

    一. 类型转换函数 类型转换函数用于更改参数的类型. 以下函数位于表达式编辑器的"类型转换"类别中.方括号表示参数是可选的.缺省日期格式为 %yyyy-%mm-%dd. 以下示例按 ...

  6. python练习册 每天一个小程序 第0001题

    1 # -*-coding:utf-8-*- 2 __author__ = 'Deen' 3 ''' 4 题目描述: 5 做为 Apple Store App 独立开发者,你要搞限时促销,为你的应用生 ...

  7. 【基础】java环境搭建及配置--->【关注微信公众号:三叔测试笔记,及时获取干货】

    一.下载安装 Java官网下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.ht ...

  8. Golang 包了解以及程序的执行

    Golang 包了解以及程序的执行 引言  Go 语言是使用包来组织源代码的,包(package)是多个 Go 源码的集合,是一种高级的代码复用方案.Go 语言中为我们提供了很多内置包,如 fmt.o ...

  9. Redis+Caffeine两级缓存,让访问速度纵享丝滑

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 在高性能的服务架构设计中,缓存是一个不可或缺的环节.在实际的项目中,我们通常会将一些热点数据存储到Redis或MemCache这类缓存中间件中, ...

  10. Map的野路子

    首先有一张user数据表,数据库名称为mybatis,数据如下: 我们使用以下两种方式实现数据更新的操作. 方式一 UserMapper.java如下: /** * @description: 更改用 ...