【TCP通信】原理详解与编程实现(一)

6 篇文章 2 订阅
订阅专栏


本文主要是对韩立刚计算机网络视频课程TCP通信部分的总结和整理,并参考了其它相关博客。
本文主要是理论知识。
下一篇文章将进行编码实现 【TCP通信】原理详解与编程实现(二)

1.TCP简介

TCP协议,传输控制协议(英语:Transmission Control Protocol,缩写为:TCP)是一种面向连接的、可靠的、基于字节流的通信协议

TCP把连接作为最基本的抽象单元,每条TCP连接有两个端点,TCP连接的端点即套接字
套接字socket = (IP地址+端口号)
TCP连接={socket1,socket2}={(IP1:port1),(IP2,port2)}
TCP提供全双工通信。

2.TCP报文

首部中的重要概念
序号:Seq序号,占32位。用于说明当前数据第一个字节在所有数据(整个文件)中的位置
确认号:Ack序号,占32位。用于告诉发送者接下来需要发送的数据序号。
数据偏移:用于说明首部长度。(比如1111说明首部长为15*4字节)
标志位:tcp标志位有6种:

SYN(synchronous发起一个新连接) 
ACK(acknowledgement 确认)
PSH(push传送) 
FIN(finish结束)
RST(reset重置) 
URG(urgent紧急)

不要将确认序号Ack与标志位中的ACK搞混
窗口:表示发送/接收缓存窗口大小。如下图。
在这里插入图片描述

3.TCP建立与断开连接

3.1 TCP的三次握手

三次握手其实就是建立连接的过程。其过程如图:

1)第一次握手:Client将标志位SYN(建立新连接)置为1,随机产生一个值seq=x,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
2)第二次握手:Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYN和ACK(确认)都置为1ack=x+1,随机产生一个值seq=y,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
3)第三次握手:Client收到确认后,检查ack是否为x+1,ACK是否为1,如果正确则将标志位ACK置为1,ack=y+1,并将该数据包发送给Server,Server检查ack是否为y+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

三次握手的通俗理解

3.2 TCP的四次挥手

四次挥手其实就是断开连接的过程。过程如图:

1)第一次挥手:客户端向服务器发起请求释放连接的TCP报文,置FIN为1。客户端进入终止等待-1阶段
2)第二次挥手:服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,服务器端进入CLOSE-WAIT阶段,并向客户端发送一段TCP报文。客户端收到后进入种植等待-2阶段

3)第三次挥手:服务器做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文。。此时服务器进入最后确认阶段
4)第四次挥手:客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,于是进入时间等待阶段,并向服务器端发送一段报文。注意:第四次挥手后客户端不会立即进入closed阶段,而是等待2MSL再关闭。

四次挥手的通俗理解

4.TCP数据传输示意

以下图为例(计算机访问一个网站)说明传输过程:

1)计算机访问网站,源端口为1057,目标端口为80,序号为1,确认号为1,数据长203字节。
2)网站返回数据,确认号为204,发送1-1460数据。
3)网站接着发1461-2053数据,确认号依然为204.(表明计算机发的203个字节已经接收到)
4)计算机确认收到2053字节的数据,但自身发送的数据为空。

5.TCP如何实现可靠传输

5.1 停止等待方式

需要停止等待确认,若设定时间内未收到确认则进行超时重传。这样可以保证对方确认收到后,再发送下一段报文。

确认丢失与确认迟到

上述的确认和重传机制,可以称为自动重传机制ARQ(Automatic repeat reQuest)
但是简单的停止等待方式信道利用率较低,为此采用流水线传输方式

5.2 流水线传输方式

流水线传输
发送方可连续发送多个分组,不必每发完一个分组就停顿下来等待对方的确认。由于信道上一直有数据不间断的传送,这种传输方式可获得很高的信道利用率。

连续ARQ协议 / 滑动窗口
上述发送端是维持滑动窗口实现流水线传输的,如下图:

累计确认
接收方一般采用累计确认的方式表明自己已经连续接收到哪个地方了

5.3 可靠传输实例:

前面已经简单说明了tcp可靠传输的大致原理。这里具体举例说明。
假设,A计算机要发送一个文件(1-40字节)到B计算机
1)首先计算机A将缓存中的数据依次发送出去(多个数据包),在B确认之前将不会删除这些数据

2)计算机B确认收到前两个数据包,并发送一个数据包(确认号为7)给A,于是A知道前6个字节已经发送成功,缓存窗口可以移动,舍弃前6个字节.

3)A继续发送窗口中的数据,B的接收窗口右移,B又接收到新数据,再向A确认新数据收到,A继续发送新数据。

4)丢包的情况
假设A发的三个数据包中,只有第二个丢了,而一、三数据包没有丢,那么B只会确认第一个数据包,于是A超时重传第二个数据包,B重新接收到第二个数据包后,会直接确认第三个数据包,这样A就不用重传第三个数据包了。

6.TCP流量控制

TCP流量控制
概念
接收端处理数据的速度是有限的,如果发送方的速度太快,就会把缓冲区u打满。这个时候如果继续发送数据,就会导致丢包等一系列连锁反应。所以TCP支持根据接收端能力来决定发送端的发送速度。这个机制叫做流量控制。

窗口大小
(接收端向发送端主机通知自己可以接受数据的大小,这个大小限制就叫做窗口大小)

机理
接收端将自己可以接收的缓冲区大小放入 TCP 首部中的 “窗口大小” 字段, 通过ACK端通知发送端;窗口大小字段越大, 说明网络的吞吐量越高;
接收端一旦发现自己的缓冲区快满了, 就会将窗口大小设置成一个更小的值,通知给发送端;发送端接受到这个窗口之后, 就会减慢自己的发送速度;
如果接收端缓冲区满了, 就会将窗口置为0; 这时发送方不再发送数据, 但是需要定期发送一个窗口探测数据段, 使接收端把最新的窗口大小告诉发送端,以便继续发送数据。

其过程示意如图
在这里插入图片描述

7.TCP拥塞控制

在不清楚当前网络状态下, 贸然发送大量的数据, 可能引起计算机网络的拥堵.
TCP引入慢启动机制, 先发少量的数据, 探探路, 摸清当前的网络拥堵状态, 再决定按照多大的速度传输。如下图:
在这里插入图片描述
每次发送数据包的时候, 将拥塞窗口和接收端主机反馈的窗口大小做比较, 取较小的值作为实际发送的窗口;像上面这样的拥塞窗口增长速度, 是指数级别的. “慢启动” 只是指初使时慢, 但是增长速度非常快. 为了不增长的那么快, 因此不能使拥塞窗口单纯的加倍.此处引入一个叫做慢启动的阈值

当拥塞窗口超过这个阈值的时候, 不再按照指数方式增长, 而是按照线性方式增长

乘法减少:出现一次超时(即出现一次网络拥塞),就把慢开始门限值ssthresh设置为当前的拥塞窗口值乘以0.5
在这里插入图片描述

8.TCP相关面试题

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。
但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

【问题2】为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才能返回到CLOSE状态?

答:虽然按道理,四个报文都发送完毕,我们可以直接进入CLOSE状态了,但是我们必须假象网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。在Client发送出最后的ACK回复,但该ACK可能丢失。Server如果没有收到ACK,将不断重复发送FIN片段。所以Client不能立即关闭,它必须确认Server接收到了该ACK。Client会在发送出ACK之后进入到TIME_WAIT状态。Client会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么Client会重发ACK并再次等待2MSL。所谓的2MSL是两倍的MSL(Maximum Segment Lifetime)。MSL指一个片段在网络中最大的存活时间,2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。

【问题3】为什么不能用两次握手进行连接?

答:3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。

现在把三次握手改成仅需要两次握手,死锁是可能发生的。作为例子,考虑计算机S和C之间的通信,假定C给S发送一个连接请求分组,S收到了这个分组,并发送了确认应答分组。按照两次握手的协定,S认为连接已经成功地建立了,可以开始发送数据分组。可是,C在S的应答分组在传输中被丢失的情况下,将不知道S 是否已准备好,不知道S建立什么样的序列号,C甚至怀疑S是否收到自己的连接请求分组。在这种情况下,C认为连接还未建立成功,将忽略S发来的任何数据分 组,只等待连接确认应答分组。而S在发出的分组超时后,重复发送同样的分组。这样就形成了死锁。

【问题4】如果已经建立了连接,但是客户端突然出现故障了怎么办?

TCP还设有一个保活计时器,显然,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

参考

《计算机网络》视频课程韩立刚

详解 TCP 连接的“ 三次握手 ”与“ 四次挥手 ”

Java基于Socket实现网络编程实例详解
09-02
Java基于Socket实现的网络编程是Java开发者在构建网络应用程序时常用的一种技术。Socket是网络通信中的一个重要概念,它为两台计算机之间的数据交换提供了接口。本文将深入探讨Java中的Socket编程,以及TCP和UDP两种...
windows 网络通信 socket编程详解 快速入门
04-08
TCP/IP体系结构   TCP/IP协议实际上就是在物理网上的一组完整的网络协议。其中TCP是提供传输层服务,而IP则是提供网络层服务。 套接字   套接字是网络的基本构件。它是可以被命名和寻址的通信端点,使用中的每一个套接字都有其类型和一个与之相连听进程。套接字存在通信区域(通信区域又称地址簇)中。套接字只与同一区域中的套接字交换数据(跨区域时,需要执行某和转换进程才能实现)。WINDOWS 中的套接字只支持一个域——网际域。套接字具有类型。 基本套接字   为了更好说明套接字编程原理,给出几个基本的套接字,在以后的篇幅中会给出更详细的使用说明。 客户机/服务器模式   在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model)
TCP协议中,Socket编程通信原理深度解析
11-12
本文档分析了TCP协议中利用Socket编程使用的一些重要函数,并深入分析了Socket通信使用的一些技术。
TCPTCP客户端、服务器如何通信
最新发布
BEIFEN13的博客
05-06 2363
TCP客户端、服务器如何通信,讲解了bind,listen,accept 等函数,与UDP的差别等等
C语言编写基于TCP和UDP协议的Socket通信程序示例
09-02
主要介绍了C语言编写基于TCP和UDP协议的Socket通信程序示例,其中TCP的客户端与服务器端采用多线程实现,需要的朋友可以参考下
传输层协议 —— TCP(图解1)
M的博客
12-03 1271
目录一、TCP的基本认识1. TCP头部格式2. TCP协议的特点3. 什么是TCP连接4. TCP如何封装与分用 二、通过序列号和确认应答号提高可靠性1. 32位序列号2. 32位确认应答号3. 保证可靠性 4. 为什么序列号和确认应答号是单独的字段三、窗口大小1. TCP的发送和接收缓冲区2. 窗口大小 四、TCP连接建立1. TCP三次握手全过程 2. 为什么是三次握手?不是两次、四次? 3. 第一次握手失败,会发生什么?4. 第二次握手失败,会发生什么?5. 第三次握手失败,会发生什么?...
绕不开的TCP之三次握手
测试架构师养成记的博客
10-09 1103
在面试过程中,无论是开发还是测试岗位,TCP都是一个绕不开的话题,而谈到TCP,大概率三次握手也会被提及,那应该如何回答这个问题呢?在回答这个问题之前,让我们先预热一波吧。 TCP的定义 TCP协议全称: 传输控制协议, 顾名思义, 就是要对数据的传输进行一定的控制,它是一种面向连接的、可靠的、基于字节流的传输层通信协议。 TCP连接全过程的状态 TCP连接全过程中,客户端及服务端存在的状态如下:...
TCP详解
热门推荐
长岛冰茶去冰的博客
04-20 1万+
详细介绍TCP的相关知识,如有错误或不足,欢迎指正!
TCP协议
ZH的博客
05-13 1902
TCP(Transmission Control Protocol)是面向连接的可靠的通讯协议。TCP需要经过三次握手建立连接,并在断开时通过四次挥手释放连接。TCP通过应答确认、超时重传(RTO)、往返时延(RTT)、数据排序、流量控制、全双工通讯的机制和特性,保证连接的可靠性。
TCP通信过程详解以及tcp长连接和短连接
LinkSLA的博客
07-21 638
在长连接的应用场景下,client端一般不会主动关闭它们之间的连接,Client与server之间的连接如果一直不关闭的话,会存在一个问 题,随着客户端连接越来越多,server早晚有扛不住的时候,这时候server端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可 以避免一些恶意连接导致server端服务受损;总之,长连接和短连接的选择要视情况而定。长连接和短连接的产生在于client和server采取的关闭策略,具体的应用场景采用具体的策略,没有十全十美的选择,只有合适的选择。
【网络】TCP通讯(三次握手、四次挥手;滑动窗口;TCP状态转换;端口复用;TCP心跳检测机制)
crr411422的博客
05-08 4718
1)建立连接(三次握手)的过程;2)数据传输的过程;3)关闭连接(四次挥手)的过程;半关闭:此时A可以接收B发送的数据,但是A已不能再向B发送数据。TCP异常断开: 心跳检测机制:在TCP网络通信中,经常会出现客户端和服务器之间的非正常断开,需要实时检测查询链接状态。常用的解决方法就是在程序中加入心跳机制。1)Heart-Beat线程;2)设置TCP属性;
详解C# 网络编程系列:实现类似QQ的即时通信程序
01-21
前面专题中介绍了UDP、TCP和P2P编程,并且通过一些小的示例来让大家更好的理解它们的工作原理以及怎样.Net类库去实现它们的。为了让大家更好的理解我们平常中常见的软件QQ的工作原理,所以在本专题中将利用前面专题...
C++ boost::asio编程-同步TCP详解及实例代码
12-31
boost.asio库是一个跨平台的网络及底层IO的C++编程库,它使用现代C++手法实现了统一的异步调用模型。 boost.asio库支持TCP、UDP、ICMP通信协议。 下面介绍同步TCP模式: 大家好!我是同步方式! 我的主要特点...
SNMP 原理与实战详解SNMP协议详解.docx
05-24
SNMP 原理与实战详解 SNMP(Simple Network Management Protocol,简单网络管理协议)是一种网络管理协议,用于管理网络设备。SNMP 的工作方式包括“读”操作、“写”操作和“Trap”操作。管理员可以使用 SNMP 协议...
TCP通信原理
12-08 4984
TCP协议用来控制两个网络设备之间的点对点通信,两端设备按作用分为客户端和服务端。服务端为客户端提供服务,通常等待客户端的请求信息,有客户端请求到达之后,及时提供服务和返回响应消息;客户端向服务端主动发出请求,并接受响应消息。 首先启动服务端程序,并开始等待网络中的客户请求,然后客户端主动向服务端发出连接请求,服务端接收到客户端的连接请求后,并和客户端之间建立一个稳定的TCP/IP通信连接。 现在客户端将向服务端主动发出请求,服务端接收客户端消息,并及时返回响应消息。这是通过IO流(字节流)实现的。
windows - TCP通讯流程
m0_52006268的博客
06-16 1277
TCP建立连接的过程叫做握手握手需要在客户和服务器之间交换三个TCP报文段,称为三次握手采用三次握手主要是为了防止已失效的连接请求报文段 突然又传送到了,因而产生错误。客户端将TCP报文,保存在TCP首部的序列号(Sequence Number)字段里,指明客户端打算连接的服务器的端口,并将该数据包发送给服务器端,发送完毕后,客户端进入SYN_SENT状态,等待服务器端确认。服务器端收到数据包后,并将该数据包发送给客户端以确认连接请求,服务器端进入SYN_RCVD状态。客户端收到确认后,
TCP通信协议
qq_20312079的博客
01-17 2135
分片不同TCP 的数据大小如果大于 MSS 大小,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了一个分片,只需要传输丢失的这个分片UDP 的数据大小如果大于 MTU 大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层,但是如果中途丢了一个分片,则就需要重传所有的数据包,这样传输效率非常差,所以通常 UDP 的报文应该小于 MTU。所以当服务端出现大量 TIME_WAIT 时,系统资源被占满时,会导致处理不过来新的连接。
qt 网络编程实现tcp通信
08-01
在Qt中实现TCP通信可以使用QTcpSocket和QTcpServer两个类。QTcpSocket代表了两个独立的数据流,一个用来读取数据,一个用来写入数据。可以使用QTcpSocket::read()和QTcpSocket::write()操作来读取和写入数据。在读取数据之前,可以使用QTcpSocket::bytesAvailable来确定是否有足够的数据可用。而QTcpServer用于处理客户端的连接,可以使用QTcpServer::listen()来监听客户端发来的连接请求。每当有客户端连接时,QTcpServer会发射newConnection()信号,可以使用QTcpSocket来读取客户端发来的数据报,也可以发送数据报。[2] 因此,要在Qt中实现TCP通信,你可以创建一个QTcpSocket对象作为客户端,使用QTcpSocket::connectToHost()方法连接到服务器,并使用QTcpSocket::write()方法发送数据。在服务器端,你可以创建一个QTcpServer对象,使用QTcpServer::listen()方法监听客户端的连接请求,并在newConnection()信号触发时使用QTcpServer::nextPendingConnection()方法获取与客户端通信的QTcpSocket对象,然后使用QTcpSocket::read()方法读取客户端发送的数据。[1]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • 【TCP通信】原理详解与编程实现(一) 16029
  • [c++] 常成员函数 14119
  • CUDA多版本切换(软链接) 10368
  • [c++] 函数指针(将函数名作为参数传递给函数) 10222
  • ubuntu16.04下PCL点云库的最新安装方法与简单测试 10093

分类专栏

  • SQL笔记 5篇
  • java杂记
  • 计算机相关 6篇
  • 算法/数据结构 11篇
  • linux相关 6篇
  • c++ 30篇
  • 其他
  • QT 2篇
  • slam 6篇
  • opencv 3篇
  • 深度学习 7篇
  • 安装调试记录 7篇

最新评论

  • [c++] 常成员函数

    m0_74756750: 重载函数那里的常对象a为什么可以调用构造函数呢?构造函数是常成员函数吗?

  • 【TCP通信】原理详解与编程实现(一)

    LiuAdvance498: 你这个是真的好啊表情包,为什么我现在才看见啊

  • ros_多消息同步回调(Synchronizer)

    甲壳虫奇袭电脑城: 这个是boost::bind 的用法,相当于回调函数的即将输入的参数1,和参数2

  • [c++] 常成员函数

    挺好1: 第一个代码没有构造函数

  • ros_多消息同步回调(Synchronizer)

    汤依灵: 请问sync.registerCallback(boost::bind(&callback, _1, _2));后面那个_1,_2参数代表什么意思啊

您愿意向朋友推荐“博客详情页”吗?

  • 强烈不推荐
  • 不推荐
  • 一般般
  • 推荐
  • 强烈推荐
提交

最新文章

  • 【MySQL基础】MySQL中的数据结构&B+树
  • MySQL索引-3回表查询与覆盖索引
  • MySQL索引-2聚集索引探讨
2022年5篇
2020年25篇
2019年52篇

目录

目录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳SEO优化公司民治建设网站民治模板制作坂田百姓网标王吉祥网站优化排名大浪百搜词包广州建站沙井设计公司网站观澜百度关键词包年推广荷坳百度网站优化排名永湖百度关键词包年推广大鹏网络广告推广丹竹头关键词按天计费坑梓百度竞价包年推广大鹏SEO按天收费南澳关键词排名坪地网站搜索优化爱联百度竞价龙华网站优化排名南联网络广告推广惠州百度竞价观澜网站优化排名大运网络推广盐田百度网站优化排名木棉湾如何制作网站南山网站改版坪山网站推广工具民治关键词按天收费永湖模板制作光明企业网站设计木棉湾百度seo歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化