learn.lianglianglee.com/专栏/全解网络协议/14 我那不为人知的秘密是什么 - TCP(二).md.html
2022-05-11 18:57:05 +08:00

773 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>14 我那不为人知的秘密是什么 - TCP.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/全解网络协议/01 我应该站在谁的肩膀上 - OSI vs TCPIP模型.md.html">01 我应该站在谁的肩膀上 - OSI vs TCPIP模型.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/02 万丈高楼平地起- 物理层 + 数据链路层.md.html">02 万丈高楼平地起- 物理层 + 数据链路层.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/03 OSI的灵魂就是我 - 网络层.md.html">03 OSI的灵魂就是我 - 网络层.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/04 要快还是要稳你说好了 - 传输层.md.html">04 要快还是要稳你说好了 - 传输层.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/05 是时候展现真正的技术了 - 应用层.md.html">05 是时候展现真正的技术了 - 应用层.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/06 重回小学课堂 - 二进制101.md.html">06 重回小学课堂 - 二进制101.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/07 1+1 = 2吗 - 二进制的计算.md.html">07 1+1 = 2吗 - 二进制的计算.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/08 16进制又是个什么鬼 - 16进制的讲解.md.html">08 16进制又是个什么鬼 - 16进制的讲解.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/09 我想有个家 - 什么是IP地址.md.html">09 我想有个家 - 什么是IP地址.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/10 我可是住二环的人 - IP地址的组成和分类.md.html">10 我可是住二环的人 - IP地址的组成和分类.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/11 我已经没地方住了吗 - IPv6.md.html">11 我已经没地方住了吗 - IPv6.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/12 向左还是向右 - IP路由.md.html">12 向左还是向右 - IP路由.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/13 我能给你安全感 - TCP.md.html">13 我能给你安全感 - TCP.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/全解网络协议/14 我那不为人知的秘密是什么 - TCP.md.html">14 我那不为人知的秘密是什么 - TCP.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/15 不问收没收到,就问快不快 - UDP.md.html">15 不问收没收到,就问快不快 - UDP.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/16 我为什么与众不同 - TCP高级篇拥塞模型.md.html">16 我为什么与众不同 - TCP高级篇拥塞模型.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/17 来,先看看我的家谱 - HTTP的身世.md.html">17 来,先看看我的家谱 - HTTP的身世.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/18 我都这么成功了,你却说我不行 - HTTP 的特点和缺点.md.html">18 我都这么成功了,你却说我不行 - HTTP 的特点和缺点.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/19 我老了,让我儿子来吧 - HTTP2.md.html">19 我老了,让我儿子来吧 - HTTP2.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/20 稳重的大外甥 - HTTPS.md.html">20 稳重的大外甥 - HTTPS.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/21 HTTP的高级篇 - HTTPClientJava.md.html">21 HTTP的高级篇 - HTTPClientJava.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/22 想来我家,你自己查呀 - DNS.md.html">22 想来我家,你自己查呀 - DNS.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/23 来的早,不如来得巧 - NAT.md.html">23 来的早,不如来得巧 - NAT.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/24 辛苦的邮政 - SMTP.md.html">24 辛苦的邮政 - SMTP.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/25 你就是看不见我 - VPN.md.html">25 你就是看不见我 - VPN.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/26 黑客的好帮手 - SSH.md.html">26 黑客的好帮手 - SSH.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/27 你可以得到我的心,却得不到我的人 - 物理安全设备.md.html">27 你可以得到我的心,却得不到我的人 - 物理安全设备.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/28 你怎么证明你就是你 - 身份验证和访问控制.md.html">28 你怎么证明你就是你 - 身份验证和访问控制.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/29 我要怎么藏好我的考研资料 - 网络攻击(一).md.html">29 我要怎么藏好我的考研资料 - 网络攻击(一).md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/30 我要怎么藏好我的考研资料 - 网络攻击(二).md.html">30 我要怎么藏好我的考研资料 - 网络攻击(二).md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/31 如何保护我的考研资料 - 网络攻击防范.md.html">31 如何保护我的考研资料 - 网络攻击防范.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/32 Linux网络安全 - 安全实战.md.html">32 Linux网络安全 - 安全实战.md.html</a>
</li>
<li>
<a href="/专栏/全解网络协议/33 结语.md.html">33 结语.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>14 我那不为人知的秘密是什么 - TCP</h1>
<p>我们之前学习IP的时候就是把IP的header彻底的分析了一番是不是既然我已经给自己挖了这个坑就一定要把这个坑填好我们现在来一起学习一下TCP的header。</p>
<h3>TCP Header</h3>
<p><img src="assets/20210205165519703.png" alt="在这里插入图片描述" /></p>
<p>上图就是一个TCP Header的文件。我们还是一点点的来分析。 Source Port源端口源TCP的用户 Destination Port目标端口目标TCP 用户的端口 Sequence Number序列号: 第一个数据字节的序列号SYN标志除外。如果设置了SYN则此字段包含初始序列号ISN。下面的例子很严重依赖这个序列号你想不明白都难。 Acknowledgment Number确认号: 包含TCP期望接收的下一个数据的序列号。 Data Offset数据偏移: 头中32位字的数量。 Reserved保留: 为以后保留使用。 Flags标识:这里有几种数值,我在下面扩展讲。 Window 窗口大小TCP流量控制的一个手段用来告诉对端TCP缓冲区还能容纳多少字节。 CheckSum校验: 由发送方填充接收方对报文段执行CRC算法以检验TCP报文段在传输中是否损坏。 Urgent Pointer紧急指针一个正的偏移量它和序号段的值相加表示最后一个紧急数据的下一字节的序号接收方可以通过此来知道有多少紧急的数据用过来。 Options + Padding:可选和填充项。</p>
<h5>Flags</h5>
<p>CWR拥塞窗口减少标志 ECE: ECN响应标志被用来在TCP3次握手时表明一个TCP端是具备ECN功能的 URG: 紧急标志 ACK: 确认标志,还记得三次握手吗 RST: Reset连接看林志玲内衣的例子我相信你一辈子都不会忘 SYN: 同步序列号 FIN: 发送方没有数据了,想想四次分手</p>
<p><img src="assets/2021020516572098.png" alt="在这里插入图片描述" /></p>
<p>我们来看一下这个图这个还是用wireshark抓下来的包你可以从图上清楚的看到我们上面讲的TCP header都在实际的包中。</p>
<h3>那背后无形的大手</h3>
<p>我们现在开始进行更深层次的讨论那就是TCP如何提供可靠的传输呢简单的说就是使用序列号和确认号。</p>
<p>到目前为止我们了解了三次握手以及握手背后的本质。其中包含SYNSYN-ACK和ACK。然后建立连接开始通信。我们现在就来看一下通信是怎么实现的比如说下面这个图 <img src="assets/20210205165738997.png" alt="在这里插入图片描述" /></p>
<p>客户端要从服务器获得这个精美的图片但是图片太大不可能一次性的发送服务器要做的就是把它分割成几个部分。还记得我们之前看的那个Segment部分里的Payload吗这个图片就可以放到那个部分。这个payload最大可以使用的容量是1460 bytes所以你不能放超过这个限制的数据。我们之前的那个Segment里面是不是还有序列号和确认号。因为我们还没有发送或者接收任何的数据。所以我们可以给这个序列号为1。确认号也是1。序列号代表我发送的数据的第一个字节数。我还没有发送任何数据所以最开始是1。我把这个图片分成固定的大小比如说每一小部分就是250 bytes那么我们上面说的最大容量是1460 bytes。所以我们可以在这个payload里面放五个图片分割之后的部分对不对。那就是1250 bytes然后把这个Segment包装到Packet里然后从服务器端发送到客户端。 然后客户端收到这个Packet是不是要开始剖洋葱把Packet打开从Segment里面取出这5个分割的图片部分然后组装这个图片。客户端这个时候已经收到了从1到1250字节的数据对不对。然后该到客户端操作了。</p>
<p>客户端也要开始构建自己的Segment了这个Segment要确认收到了刚刚的1250 bytes的图片数据。这里要注意客户端发送的这个序列号还是1为什么呢因为客户端还没有发送任何的数据给服务器对不对所以序列号还是1。客户端可以发数据也可以不发数据我们这里比较重要的是什么是这个确认号现在的确认号是1251。聪明的你会不会问为什么是1251不是1250这里你要记住这个确认号要永远比你接收到的最大的字节数加1因为客户端收到了1-1250之所以要发送回1251是为了告诉服务器你现在可以发送1251这个字节后面的数据了。然后把这个Segment封装到Packet里发送给服务器。</p>
<p>服务器收到之后打开这个包裹看到消息说好的你已经收到了1-1250我现在开始发送1251是不是又可以放5个图片的部分到payload然后把序列号改成1251确认号还是1然后走你再发送给客户端。</p>
<p>客户端这个时候还是重复上面的动作拆开包裹取出照片组合收到的照片部分。也许你还很年轻但是在大概1992年的时候下载图片其实就是这样你会发现没有下载完的图片会一点点的展示有的部分有有的没有。当然我这里只是给你掰开了细细的讲。让你可以明白的更加透彻。这个时候客户端又要重新构建了你自己想一下这个确认号和序列号应该是什么是不是序列号还是1因为还是没有数据要发送给服务器然后确认号这个时候是2501了吧。因为客户端已经收到了2500 bytes了。需要告诉服务器的是我要开始接收2501以后的字节了。</p>
<p>然后这个球又到了服务器这边了我就不再讲的那么细致了简写一下就是现在的新Segment是不是序列号变成2501了确认号还是1。世界不可能永远那么美好。这个时候当服务器把这个消息发给客户端的时候由于某种原因可能是哥斯拉入侵。这个消息弄丢了。世界末日了吗当然不会。这个时候是TCP展现真正技术的时候了。我们来看一下TCP是如何解决这个问题的。</p>
<p>现在数据丢了但是服务器还不知道这个消息是不是丢了因为它只是发出去了一个消息后面什么都不知道了。当然客户端也不知道发生了什么。因为客户端什么都没有收到。当然我们这里是放慢了100倍的来讲解实际上在现实中如果一个packet丢失了服务器那边可能已经开始发送新的Packet了Anyway我们继续我们这边的慢动作。服务器那边因为不知道发生了什么又继续发了一个新的Packet序列号是3751。当客户端收到这个包裹的时候会放到对应的位置但是问题来了。是不是缺少2501-3750这个部分。这个时候客户端会发送一个特殊的Segment在FLAG部分发送的是SACK也就是Selective ACK, 确认号是5001 2501-3750。这说明什么意思呢这是告诉服务端我收到了5000但是2501-3750我没有收到。所以我需要5001之后的部分以及2501-3750这部分。客户端把这Segment打包好后发给服务器。</p>
<p>服务器收到了之后呢自然表示很惊讶对不对但是作为信誉极好的卖家来说既然快递丢了我已经重新发送于是又重新构建了一个新的Segment包含2501-3750这部分的数据发送给客户端。不可能总是丢同一个包裹吗这次就很正常的发送给了客户端。客户端收到了之后就又开始拆包组装。客户端知道应该要放到哪里因为有序列号告诉客户端这个数据要放到哪里。然后再发送会ACK的Segment告诉服务器我现在需要5001以后的数据。然后发给服务器。</p>
<p>这个时候服务器把最后的部分都发送给了客户端客户端也完美的拼接好了照片但是客户端不知道已经完全发送完毕了。客户端会继续的发送说我需要6251之后的数据。但是服务器端是知道数据已经全部发完了所以服务器会发送一个Segment其中的Flag部分是FIN。还记得这个吗这个是要开始分手的标志了。当然这个时候Payload上什么数据都没有。然后就开始了分手流程。完成了四次分手。这个会话就结束了。当然客户端会给服务端一个五星好评呀。因为毕竟没有丢失数据吗。这就是一个TCP从建立传输然后分手的全过程。这其中虽然发生了一点小意外但是TCP凭借着出色的确认号和序列号机制保住了稳定传输这个称号。</p>
<p>希望你不要觉得我讲的很啰嗦。因为我是希望你能彻底的理解这个过程,还有文字的表达毕竟不如语言表达。总之还是希望读者可以彻底的理解和掌握这部分的知识。当然如果你去阿里面试的时候,千万不要把我这一篇原原本本的讲给面试官呀,不然面试官会听睡着,然后默默的和你开启四次分手了。好。希望你可以彻底明白。</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/全解网络协议/13 我能给你安全感 - TCP.md.html">上一页</a>
</div>
<div style="float: right">
<a href="/专栏/全解网络协议/15 不问收没收到,就问快不快 - UDP.md.html">下一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"7099763ac8813cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>