营销型网站建设范文,网站开发免费,帮别人做网站自己为什么会被抓,大型门户网站建设效果再谈协议 在之前利用套接字进行通信的时候#xff0c;我们都是利用 “字符串” 进行流式的发送接收#xff0c;但是我们平常进行交流通信肯定不能只是简单的发送字符串。 比如我们用QQ进行聊天#xff0c;我们不仅需要得到对方发送的消息#xff0c;还要知道对方的昵称我们都是利用 “字符串” 进行流式的发送接收但是我们平常进行交流通信肯定不能只是简单的发送字符串。 比如我们用QQ进行聊天我们不仅需要得到对方发送的消息还要知道对方的昵称头像等一系列数据也就是说我们需要得到一个结构化的数据 而想要正确的得到一个结构化的数据就需要我们定制一层应用层协议或者使用特定的应用层协议。
应用层协议 无论是哪一层的协议我们都会给数据添加自定义的报头应用层协议的报头也不例外。 报头该层协议所需要的一些特定的数据 而只有添加了报头后再将数据根据协议内容来序列化或者反序列化才能保证正确传输数据。 序列化:将结构化的数据通过协议内容转化为可以进行网络传输的形式如字符串 反序列化:将接收到的数据通过协议内容转化为结构化的数据 而添加报头就需要明确报文和报文边界有以下三种方式
定长使用固定的长度表示报文特殊符号用特殊符号分隔报文和报头自描述方式报文内部包含了报文长度等一些能够描述报文边界位置的信息 Http协议 虽说我们能够自己定义协议但是定义协议费时费力还不能出差错。 而现实中已经有很多大佬给我们定制了现成的协议让我们使用比如——Http协议 Http默认端口---80
URL URL统一资源定位符也就是网址 http协议的URL格式如上。 实际上我们访问的资源都是存储在对应网站的服务器的磁盘上的因此我们访问的URL也需要带上访问的文件的路径。 而这个服务器地址就是服务器的ip地址。 最后ip地址加上端口号和文件路径就能够成功的请求到服务器的资源。
urlencode和urldecode 在URL中有一些特殊字符被当做特殊意义理解了比如 /, 之类的因此当我们使用浏览器进行搜索的时候浏览器会将搜索的内容做一些特殊处理。 比如我们搜索c就会发现 这两个字符被替换成了 %2B 的样式这就是urlencode; 而 urldecode 则是将对应的字符翻译成原来的模样。
urlencode 将中文和特殊字符给转义化urldecode 将url请求中的转移化的字符进行解码 每当我们向服务器请求资源时浏览器就会向服务器发起请求。
Http请求格式 每一个浏览器向服务器发送请求时浏览器会发送这么长一串报头给服务器。 这个报头有很多信息比如 Conten-Length(正文长度)等一些信息。
首行格式 【方法】 【url】 【http协议版本】Header请求的属性冒号分割的键值对每组之间用 \n分割在Header之后便是空行body空行后面的内容都是Body Body允许为空字符串. 如果Body存在, 则在Header中会有一个 Content-Length属性来标识Body的长度 当服务器收到请求后就会发送对应的响应。
Http响应格式 首行【版本号】【状态码】【状态码解释】Header请求的属性以冒号分割的键值对每行以\n分割遇到空行Header结束body空行后就是body允许body为空字符串若body存在Header中会由一个Content-Length来表示body长度若返回的是一个html页面那个html页面内容就在body中
Http的方法 在这么多方法中Get和Post是用的最多的那么Get和Post之间有什么区别呢
使用Get方法 当我们使用Get方式提交表单的时候我们发现URL中会存在我们输入的用户名和密码 也就是说Get方法是通过URL来传参的。
使用Post方式 而是用Post方式来访问则不会在URL中看到账号和密码 Post方式中的账号和密码都是存储在正文当中的。 Get和Post的区别
Get通过URL传参Post通过正文传参Post更有私密性Get能够传递的参数长度有限Post则没有该限制Get请求的参数会保存在浏览器记录中Post则不会 虽说Post更具有私密性但是实际上它们二者都不是安全的只是Post更加具有私密性罢了
Http状态码 常见的状态码有 200(OK),404(Not Found),403(Forbidden),302(Redirect)等等。 其中3开头的状态码需要详细讲一下。 重定向分为临时重定向和永久重定向。
临时重定向状态码302对旧网址没有影响但新网址没有排名永久重定向状态码301新网址完全继承旧网址旧网址的排名清零
现象
永久重定向时浏览器会将输入栏网址自动更新为新网址临时重定向时浏览器的输入栏网址依旧为旧网址但是内容是新网址
Http常见Header
Content-Type数据类型text/html之类的Content-LengthBody的长度Host客户端告知服务端所请求的资源在哪个主机上User-Agent声明用户所用的操作系统和浏览器版本信息referer当前页面是从哪个页面跳转过来的location搭配3xx的状态码告知客户端跳转到哪个页面Cookie用于在客户端存储少量信息用于实现Session功能
长连接 一张完整的网页一般由多种元素组成因此需要多次请求但是http是基于TCP协议的而TCP是面向连接的因此请求一张网页也许会存在频繁创建连接的问题。 而长连接就是为了解决该问题而存在的。 它通过建立一条链接获取资源的任何行为都必须通过这个链接完成从而解决频繁创建连接的问题。
http会话保持 会话保持这个功能是用户在实际体验过程中所需要的一个功能表面现象就是当你登录了一个网站那么你即使退出了该网站或者退出了该浏览器下一次访问该网站时网站依旧知道你是哪个用户。 会话保持有两种方法。
老方法 老方法是通过在客户端保存用户信息每次访问同一个网站浏览器都会自动推送历史保留信息从而实现会话保持。 而这个信息称为cookie。 Cookie 用来保存用户信息cookie文件浏览器关闭后cookie会以文件形式保存下来cookie内存浏览器关闭后cookie不会以文件形式保存下来 但是老方法有一个问题那就是cookie信息是保存到客户端的一般的客户端很难防止木马盗取用户信息就会导致用户账号被盗。 而新方案则另辟蹊径。
新方案 新方案将用户信息存在服务器中用session保存文件并且返回对应的session id而每次客户端请求就是通过session id 来访问对应的session文件。 虽然客户端的session id 依旧可能会被盗但是这样至少可以保证用户的信息没有被泄露。 而且服务器可以通过查看用户的 ip 地址等方案来判断 session id 是否需要失效从而保证了用户信息的安全。
Https协议 了解了一些http协议的细节那么自然也需要来了解Https协议。 https协议实际上就是单纯的在http协议和传输层之间添加了一层加密协议从而保证用户信息的安全。 由于http协议内容都是明文传输的因此需要添加加密协议防止用户信息被篡改。
什么是加密 将明文通过一系列变换生成密文。将密文通过一系列变换生成明文。 一般加密过程中都需要多个密钥来辅助加密和解密。
为什么加密 有时候我们上网下载东西时明明搜索下载的是A但是下载完却发现下载的是B这就是我们在请求下载时响应被劫持了。 我们在网络上传输的任何数据包都会经过运营商的网络设备路由器等运营商的网络设备就可以解析出你传输的数据内容并进行篡改。 当我们未被劫持时我们下载的东西就是正确的。 而当我们被劫持了下载的东西就是别的软件了。 因此我们需要通过加密来防止这种中间人攻击。
加密方式 为了防止中间人攻击https退出了两种加密方式。
对称加密
采用单钥密码系统的加密方法一个密钥可以用来加密和解密。常见算法DES3DESAESTDEARC2等。特点算法公开计算量小加密速度快加密效率高。
非对称加密
需要两个密钥来进行加密和解密分别是公开密钥public key和私有密钥private key。常见算法RSADSAECDSA。特点算法强度复杂安全性依赖于算法和密钥但是由于算法复杂使得加密速度没有对称加密快。 非对称加密有一个特点那就是两个密钥可以反着使用。 可以用公钥加密私钥解密也可以用私钥加密公钥解密。
数据摘要数据指纹
数据摘要是通过单向散列函数对信息进行运算生产一段固定长度的数字摘要。常见算法MD5SHA1SHA256等由于是将无限生产有限有可能出现碰撞但是概率很小。特点并不是一种加密方式无法通过数据摘要反推原信息通常用来进行数据对比。
数字签名
将数据摘要进行加密生产的签名。
https的加密方案 当我们了解到https的加密手段后我们再来看看加密方案。
方案一都使用对称加密 在客户端和服务器之间的交流之中都是通过客户端发送请求后服务器再将密钥X发送给客户端。 乍一看也许没问题但是如果有中间人攻击的话很容易就能将数据劫持掉。 而且由于密钥是明文传送的黑客持有了密钥后续的加密操作也没有作用了。那么无论客户端发送什么密文给服务器黑客都能够随意修改。 也许有同学会想那我将密钥给加密怎么样呢 这就陷入了一个套娃的循环了。
方案二都采用非对称加密 如图所示采用非对称加密时服务器发送的响应必须通过私钥加密但是私钥加密的密文可以通过公钥解密此时黑客已经劫持了公钥那么响应就能够被随便修改了。 方案三双方都是用非对称加密 当双方都采用非对称加密时客户端将数据通过 FS 加密因此只有服务器能够解密而服务器发送的响应能够通过客户端的 KS 加密因此只有客户端能够解密。 但是这样有一个缺点慢。 之前提过非对称加密很慢而这样双方都使用非对称加密就更慢了。
方案四对称加密非对称加密 像这样服务器明文发送了公钥给客户端客户端内部决定密钥为 X 然后通过 FS 加密发送给服务器这样客户端和服务器就通过 密钥 X 来加密而且即便中间人后面来劫持也无法篡改密文。 但是这样依旧有一个问题——那就是假如一开始中间人就开始劫持会怎么样 如果中间人一开始就劫持了那么中间人就能够篡改发送的公钥 FS这样后面的加密解密就都在中间人的监视下了。 而这个问题上面四个方案都存在。
中间人攻击 在上面几个方案中只要中间人一开始就已经开始攻击了那么中间人能够轻易获取公钥并篡改公钥为中间人自己的公钥而且服务器和客户端都无法察觉这样客户端和服务器之间的交流都会被中间人获取到。
服务器具有⾮对称加密算法的公钥S私钥S中间⼈具有⾮对称加密算法的公钥M私钥M客⼾端向服务器发起请求服务器明⽂传送公钥S给客⼾端中间⼈劫持数据报⽂提取公钥S并保存好然后将被劫持报⽂中的公钥S替换成为⾃⼰的公钥M 并将伪造报⽂发给客⼾端客⼾端收到报⽂提取公钥M(⾃⼰当然不知道公钥被更换过了)⾃⼰形成对称秘钥X⽤公钥M加密X形成报⽂发送给服务器中间⼈劫持后直接⽤⾃⼰的私钥M进⾏解密得到通信秘钥X再⽤曾经保存的服务端公钥S加密后将报⽂推送给服务器服务器拿到报⽂⽤⾃⼰的私钥S解密得到通信秘钥X双⽅开始采⽤X进⾏对称加密进⾏通信。但是⼀切都在中间⼈的掌握中劫持数据进⾏窃听甚⾄修改都是可以的 为了解决这个问题我们需要了解一个新概念。
证书
CA认证 每个服务器在使用HTTPS之前都要向CA申请一份数字证书数字证书中包含申请者信息公钥信息等。 而有证书的服务器会将证书传输给客户端客户端直接从证书中获取公钥。 每个证书中包含了以下信息 证书发布机构证书有效期公钥证书所有者签名 CA机构中有他们自己维护的公钥和私钥由此来保证证书的可靠性。 那么具体过程是如何做的呢
数据签名 CA机构的证书通过数据签名来保证证书的可靠性。 当服务器申请证书时CA在对服务器进行审核后会为该网站专门形成数字签名。
签名 CA首先将服务器的数据通过单向散列函数来生成数据指纹。然后通过CA的私钥来生成数据签名最后将明文信息和数据签名放在一起形成证书
验证 最后客户端验证则是将证书拆开数据签名通过CA公钥解密成数据指纹(每个浏览器中都有CA的公钥)明文信息则通过散列函数生成散列值最后判断数据指纹是否相同 需要验证的信息 证书是否过期证书的发布机构是否可信验证证书是否被篡改 方案五采用证书对称加密非对称加密 最后方案5是在方案4的基础上加入证书。
在最开始建立连接后服务器发送的并非单纯的公钥而是证书当客户端收到证书的时候就需要验证证书是否可信之后再通过证书中包含的服务器的公钥来加密密钥这样后续密文的解密和加密都十分便捷了
证书有没有可能被中间人篡改
即便中间人篡改了证书他依旧没有CA机构的私钥就无法在hash后用私钥加密形成签名也就没办法对篡改后的证书形成匹配的签名若强行篡改那么客户端会检测到明文和签名解密后的值不同客户端会终止传输信息防止泄露。
证书有没有可能被整个掉包
中间人没有CA私钥因此无法制作假的证书中间人只能申请真的证书来替换证书但是证书中还有域名若是域名不一致依旧会被检测到记住中间人没有CA私钥任何证书都无法被合法修改包括自己
为什么摘要需要使用CA私钥加密 由于摘要算法的特性定长分散不可逆导致我们判断证书是否相同的标准是摘要是否一致若是不采用CA私钥加密客户端没有CA的公钥来进行解密中间人只需要将内容修改同时将摘要修改那么客户端就无法分辨了。 而有了CA私钥加密就能够保证中间人无法篡改证书了。
为什么不直接加密而先形成摘要呢 为了减少密文的长度加快数字签名的速度。
HTTPS的完整流程 总结 HTTPS工作一共有三组密钥。 非对称加密用于检验证书是否被篡改。客户端天然持有CA机构的公钥服务器发送证书给客户端客户端通过该公钥验证证书是否被篡改非对称加密用于协商对称加密的密钥。客户端在证书中获取服务器的公钥用公钥给密钥加密发送给服务器对称加密服务器和客户端通过该密钥进行加密解密。 传输层 Http和Https两个协议都是在应用层的协议而传输层则是负责将数据从发送端传输到接收端
再谈端口号 端口号是用于标示一台主机上进行通信的不同程序 在TCP/IP协议中用“源IP”“源端口号”“目的IP”“目的端口号”“协议号”这五元组来表示一个通信。 端口号划分 我们平时使用端口号时会发现有的端口号不可以使用。 这是因为端口号是有范围的。
0~1023知名端口号由HTTPSSH等广为人知的应用层协议使用1024~65535操作系统动态分配的端口号 一些知名端口号 SSH服务器22端口号ftp服务器21端口号telnet服务器23端口号HTTP服务器80端口号HTTPS服务器443端口号 平时我们自己使用端口号时需要避开这些端口号。
UDP协议
UDP协议格式 想要了解UDP协议就必须了解它的协议格式。 所谓协议实际上可以看做是结构化的数据。 UDP也不例外它的报头采用的是定长大小的策略报文包含了8字节大小的报头。 报头中包含了源端口号目的端口号报文长度等信息用来传递信息。
16位UDP长度包括报头和报文的长度若是校验出错则会直接丢弃
UDP特点
无连接知道目的端口号和IP地址即可不用建立连接不可靠没有确认机制和重传机制若因网络故障而无法发送信息给对方UDP也不会返回任何错误信息面向数据报不能够灵活的控制读写数据的次数和数量
面向数据报 UDP的特点中需要注意的是面向数据报这个特点。 使用UDP协议传输的数据一次传输的数据不能拆分也无法合并UDP会原样发送。 注意事项 由于UDP的UDP长度是16位因此UDP报文的长度最长不过64K包括报头因此我们使用UDP传输数据时需要先在应用层将数据分成64K大小后再传输接收端则在接收后手动拼装。 UDP的缓冲区
发送缓冲区UDP并没有发送缓冲区调用sendto会直接交给内核由内核将数据传给网络层协议进行后续的传输操作接收缓冲区虽然能够接受报文但是无法保证收到的报文顺序和发送的报文顺序一致 UDP客户端通过 send/write 将数据发送到网络中然后服务器把数据放到接收缓冲区中后服务器通过报头判断自己是否为目的地再从接收缓冲区中获取信息否则直接丢弃。 而UDP协议之中它的socket既可以读又可以写因此是双全工的。
基于UDP的应用层协议
NFS网络文件系统TFTP简单文件传输协议DHCP动态主机配置协议BOOTP启动协议用于无盘设备启动DNS域名解析协议
此外还有用户自己UDP程序在应用层配置的协议。
TCP协议
TCP协议全称为“传输控制协议”正如它的名字它需要对数据的传输进行详细的控制。
TCP协议格式 16位校验和发送端填充CRC校验不通过认为数据有问题丢弃。检验部分是整个报文 而我们都知道TCP协议的特点是有连接可靠面向字节流。其三大特点就是由其报头造成的。
TCP报头
TCP长度 TCP的报头是一个自描述的变长报头。 首先它的报头固定大小为20字节其中有一个变量是4位首部长度用来表示报头选项的总长度。 报头总长度4位首部长度 * 4字节。 4位首部长度的单位是4字节假设报头是40字节那么4位首部长度值为10. TCP解包就是通过4位首部长度确定报头长度然后再一直读取到下一个报头的位置就读取了一个完整的报文了。
16位窗口大小 在TCP传输中传输数据的速度不可过快过慢应该根据对方的接收缓冲区的剩余空间大小来决定发送多少数据。 因此使用TCP发送数据时都会往16位窗口大小填充自己接收缓冲区的剩余空间大小来进行流量控制。
六个标记位 我们TCP平时可能会传各种各样的数据有的是普通的数据段有的是确认数据段(ACK)。 因此TCP协议使用了六个标记位来表示不同的报文。 ACK确认标记位表示是否为确认报文PSH对方的接收缓冲区已满时告知对方尽快读取缓冲区中的数据URG表示紧急指针是否有效RST对方要求重新建立连接带有RST的报文称为复位报文段SYN请求报文段携带该标记位的称为同步报文段FIN通知对方本端要关闭了带有FIN的称为结束报文段 其中有几个标记位需要展开说明。 URG标记位 一般报文都会有序号保证报文按序到达但是有时候也有高优先级的报文这时候就需要插队了。 带有URG标识位的报文就表示该数据要尽快读取。 这种报文就需要去16位紧急指针该指针通过记录紧急数据在有效载荷的偏移量来指向紧急数据。 一般紧急数据只有一字节。 RST标记位 若是三次握手与四次挥手失败了或者说通信过程中单方面出错了出错的一方认为连接不存在了 但是对方依旧认为连接存在对方依旧会发送报文此时出错的一方收到报文后就会返回一个带有RST的报文来重新建立连接。 TCP的可靠性 TCP有一个最大的特点就是它的可靠性它能够保证数据能够成功传输给对方若是失败也会告知用户那么它是如何做到的呢 用过网购的童鞋们都知道我们收到网购的东西后需要在软件上确认收货商家才能收款否则商家就无法确认你是否收到了商品。 而TCP也是如此当客户端发送请求或者数据给服务器时服务器需要返回一个确认数据段给客户端这样客户端才能知道服务器确实收到了数据。 当然这里服务器并不是单纯的返回一个确认数据段而是一段报文该报文的报头有一段数据就是确认数据段在TCP中这段确认数据段就是报头中的32位确认序号。
确认应答ACK机制 每次TCP的发送段发送数据的时候TCP协议会给每一个字节的数据添加一个序号这个序号记录在32位序号中当接收段接收数据的时候接收端会根据这个序号进行排序并判断是否丢失数据。 而当接收端返回一个ACK时就会在32位确认序号中返回最后一个位序号的值1告知对方已成功接收确认序号之前的所有数据只用从确认序号开始发送数据即可。 这样就保证接收端能够将报文全部接收并且发送端能够知道该从哪里继续发送。 此外由于TCP协议也是全双工的双方都要相互发送数据相互应答因此会有两组序号分别记录对方的位序号。
确认应答机制 为了保证可靠性TCP还有确认应答机制。 该机制分为两种情况。 数据未发送给对方在一定时间间隔后未收到应答就重传。 数据发送到对方了但是对方的应答发送失败了。这样A在一定时间后就会重新发送一次数据。 第一种情况很简单重点是第二种情况主机B重复收到了相同的数据那么它就需要进行去重操作。 而去重操作也是通过之前的32位序号进行——通过对比数据序号来去重。 对于主机A来说它需要重新发送相同的数据那就是说发送的数据并不直接移出缓冲区而是维持一段时间也许是等到应答后也许是操作系统自己决定。
超时的时间如何定 理想情况下就是找到一个最小的时间保证确认应答会在这个时间内返回。 但是实际上由于网速不同这个时间长短时变化的过长会降低效率过短会频繁重复传包 因此TCP是动态的计算这个时间间隔。 任何操作系统都是以500ms为一个单位时间间隔都是500ms的整数倍。重发一次依旧等不到应答就等待2*500ms的时间。依旧等不到应答就重发等待4*500ms以指数增长。重传一定次数就认为对方异常关闭连接。 连接管理机制 TCP作为面向连接的协议它具有一套机制用来管理连接。 一般来说TCP每次连接都需要三次握手的每次断开连接则需要四次挥手。 三次握手 三次握手的过程
客户端应用层调用connect函数客户端TCP层状态变为 SYN_SENT 并且向服务器发送包含SYN标记位的报文作为请求连接 服务器应用层时在accept函数阻塞等待客户端请求当收到包含SYN标记位的报文时服务器TCP层状态变为 SYN_RCVD并返回一个包含 SYNACK 标记位的报文之后客户端收到报文后TCP层状态变为ESTABLISHED引用层connect函数返回客户端认为连接已建立并返回包含ACK标记位的报文服务器接收到ACK标记位的报文后也认为成功建立连接状态变为 ESTABLISHEDaccept函数返回 正常来说一次成功的建立连接过程就如上之后就能够传输数据了。 但是网络通信并不一定都一帆风顺数据总有丢包风险因此我们的三次握手过程也有可能失败。 在三次握手过程中客户端发送SYN时确认应答机制会起作用告知客户端服务器是否收到数据而客户端一旦收到 SYNACK时它就认为已经成功建立连接了因此此时客户端就不会等待应答而是直接传输数据给服务器了。 但是从服务器上来看它必须收到 ACK 才会认为成功建立连接但是ACK是会丢包的。 因此三次握手可能会出现客户端认为建立连接但是服务器却不认为在建立连接的情况。 这种情况下一般就是客户端发送数据给服务器后服务器发现未建立连接就会返回一个带有RST的报文用来重新建立连接或许也有其他方案不过大差不差。 为什么是三次握手 三次握手为什么不是一次两次或者是四次握手呢首先我们要先连接三次握手的优点。 对于TCP协议来说通信双方都是对等的双方可以互相读写信息也就是所谓的全双工。 而三次握手就是最小成本验证全双工通信是通畅的。对于客户端来说它不仅需要发送SYN报文给服务器还需要读取 SYNACK 报文对于服务器来说它也是要读取 SYN 和 ACK 两个报文发送 SYNACK 两个报文正好双方都至少读写了一次。 此外三次握手能够有效的防止单机攻击服务器。 SYN洪水一种攻击手段通过给服务器发送海量连接请求使得服务器需要维护多个半连接导致服务器资源被占用。 若是一次握手就能够成功建立连接对于客户端来说它只需要发送一个链接就好了也只需要维护一个链接但是服务器是同时维护多个链接的维护每一个连接都是需要成本的若是一次握手就会使的客户端攻击服务器的成本降低二次握手也是一样。 而多次握手则是成本又比三次握手高因此采用三次握手。
四次挥手 四次挥手过程 需要注意四次挥手并不一定是客户端关闭服务器也能主动关闭。 客户端在应用层调用 close 函数TCP层状态变为 FIN_WAIT_1并且发送 FIN 报文给服务器服务器接收到后TCP层状态变为 CLOSE_WAIT应用层 read 函数返回0并返回一个ACK 报文客户端接收到后TCP层状态变为 FIN_WAIT_2,过一段时间后服务器调用close状态变为 LAST_ACK并发送 FIN 报文给 客户端客户端收到后状态变为 TIME_WAIT并返回 ACK 报文变为 CLOSED状态服务器接收到 ACK 后状态变为 CLOSED 挥手期间双方状态发送变化
CLOSED_WAIT状态 TCP层协议规定被动关闭连接的一方需要处于CLOSE_WAIT状态这个状态会一直持续到服务器处理完数据调用 close 函数会结束。 那么也就是说我将 Sever 的 close 函数给注释掉Sever就一直是这个状态。 此时客户端还在连接中看下状态。 当我们关闭客户端时再看看状态。 发现TCPSever确实一直处于CLOSE_WAIT状态。 大量出现CLOSE_WAIT原因 服务器没有进行 close 的动作服务器有压力一直在推送消息给客户端无法进行close TIME_WAIT状态 当我们使用TCP协议使用一些端口来启动服务器时用这个端口关闭的服务器在一定时间内无法再次使用这个端口就是由于TIME_WAIT状态。 TCP协议规定主动关闭连接的一方要处于TIME_WAIT状态等待2个 MSL 后才能回到CLOSED状态。MSL在不同操作系统上的时间不同可以通过 cat /proc/sys/net/ipv4/tcp_find_timeout来查看。一般来说MSL就是一个TCP报文的最大存活时间。
那么为什么要处于TIME_WAIT状态呢 主动关闭的一方需要返回一个ACK给被动关闭的一方但是ACK可能丢包确认应答机制导致主动关闭的一方需要重新接收FIN来补发一个ACK。双方断开连接时网络中也可能还有滞留的数据需要保证这些报文已经消失。 而主动关闭连接的一方等待两个MSL后就能够保证至少补发一个ACK报文并且保证网络中的滞留数据消失。
解决办法 那么我们如何才能够快速重新使用这个端口呢就需要调用下面这个函数。 使用setsockopt()设置socket描述符的选项SO_REUSEADDR为1, 表示允许创建端口号相同但IP地址不同的多个 socket描述符 当我们调用这个函数后就能够重复使用同一个端口了。 滑动窗口 在确认应答机制中并不是每次发送数据都需要应答的因为若是每次都应答会降低性能因此每次发送数据实际上是一次发送多个数据。 发送前四段数据不用等待应答。返回的应答确认序号一定是对方已经接收到的数据的序号1就能够确认是否丢包。 在TCP的报头中有一个16位窗口大小其值是指不用等待确认应答而可以继续发送数据的最大值 其大小根据对方的接收缓冲区的剩余空间的大小而变化。 根据窗口大小我们能够一次发送多个数据但是这些数据有可能在网络中丢包根据确认应答机制需要重新发送数据而这些发送出去而未收到应答的数据就需要滑动窗口来管理。
滑动窗口如何管理的 实际上滑动窗口并不是一个真正的窗口它实际上是两个下标。 收到对方的应答后win_start会根据对方报头的32位确认序号来向后移动。win_end则会根据对方的接受缓冲区的大小来向后移动。滑动窗口的大小并不固定根据对方的接收能力有关。
如果收到的应答是滑动窗口中间或结尾的ACK怎么办 也许收到的应答并不是2001而是 4001或者直接是结尾呢 这样只有两种情况。 丢包了数据没丢但是应答丢了。数据丢包了。 首先是第一种情况这种情况下窗口是直接滑动的因为序号的定义就是对方已接收到该序号之前的所有数据因此可以直接滑动。 第二种情况也很简单根据序号定义应答的ACK应该是对方所接收到的数据的序号1因此接收端就知道哪些数据丢包了就会补发一次。 当发送端连续收到重复的应答报文后会补发一次报文。比如途中发送端接收到三次 1001的报文后它就重新发送一次 1001--2000的报文。之后接收端返回的应答就是 7001 了。这个机制称为“高速重发机制”也叫快重传。 序号还支持滑动窗口的滑动规则。 一直向右滑动空间不够了怎么办 从刚刚的说法来说发送缓冲渠的空间不是无穷的因此滑动窗口一定回到缓冲区的尾部。 实际上发送缓冲区的结构是一个环形数组因此不会出现这种情况。
流量控制 接收段处理数据的速度有限如果发的太快接收端处理不及时会出现丢包的情况因此需要流量控制。 接收端将自己的缓冲区的剩余空间大小放在报文中的窗口大小字段中通过ACK通知发送端。窗口越大吞吐量越大。接收端发现缓冲区快满了就会减小窗口大小。若是窗口设置为0发送端停止发送数据但是会定期发送窗口探测数据。 16位窗口最大为65535但是TCP窗口不止65535在报头的选项中有一个窗口扩大因子MTCP窗口大小为窗口字段的值右移M位。 拥塞控制 一般在网络上同时会有很多计算机互相通信即使TCP有滑动窗口来可靠的发送大量数据但是如果一口气就发送大量数据依旧会造成一些问题。 在客户端和服务器互相通信的时候网络中依旧有很多计算机在互相通信这样会造成网络阻塞因此服务器只应答了几条报文。 像这种大量的丢包我们就认为是网络出现了阻塞。 为了应对这种情况TCP引入了慢启动机制先发少量数据来查看网络拥堵状态再来决定传输的速度。 此处引入拥塞窗口概念 传输开始时拥塞窗口概念为1每收到一个应答拥塞窗口1每次发送数据的时候将拥塞窗口和接收段主机的窗口大小比较取较小值作为实际发送的窗口
像上图中的拥塞窗口大小按指数级增长但是拥塞窗口不能这样增长否则后期会增长过快。
因此需要一个阈值来控制速度当拥塞窗口大小超过该阈值时就需要按线性方式增长。 TCP刚启动时慢启动阈值等于窗口最大值超时重发时慢启动阈值会变成原来的一半拥塞窗口大小置1
通过拥塞控制TCP能够尽快的将数据传给对方而不对网络造成太大压力。
延迟应答 有时候接收端主机若是刚接收到报文就立马应答它的接收缓冲区可能剩余空间很小返回的窗口也很小这样发送端发送的数据也会变少。
比如接收端接收到数据后还剩500k的窗口但是它的处理速度很快也许200ms后就能够处理500k的数据这样窗口就有1m了因此接收端有时候会等一会再应答这样能够接收更多的数据 这就是延迟应答但是延迟应答也是有条件的。 数量限制每隔N个包应答一次 时间限制超过最大延迟时间就应答一次 N一般为2最大延迟时间为200ms 这样返回的窗口越大其传输的速度反而更快了。
捎带应答 有时候服务器和客户端之间是 “一发一收” 的状态这个时候服务器就能够顺带把ACK和回复的报文放一起。 比如四次挥手的过程服务器能够将最后的 ACK 和 FYN 放一起给客户端。 面向字节流 创建TCP的socket时还会创建对应的接收缓冲区和发送缓冲区。
调用write会把数据先拷贝到发送缓冲区中 过长则拆分成多个数据包发送过短则放在发送缓冲区等待合适的时机或者长度够了再发接收数据的时候也是先从网卡拷贝到接收缓冲区然后应用层调用read来从接收缓冲区拿数据这种一个链接可以写也可以读的模式称为全双工 由于缓冲区的存在TCP的读写互不影响。 可以一次写100个字节的数据也可以写100次一个字节的数据读取也是。 粘包问题 对于TCP来说TCP没有报文长度的字段只有一个序号的字段。 对于TCP来说它可以按照序号将数据排序但是从应用层来说它只看到了一连串的字符数据这样应用层就分辨不了哪个数据是哪个报文的。 为了避免这个问题就需要明确包与包之间的边界。 对于定长的包可以按固定大小读取。变长的包可以在包头的位置约定一个包总长的字段也可以在包与包之间约定一个特殊的分隔符 但是对于UDP来说就不存在这种问题了。 一个是UDP报头有一个报文长度的字段并且UDP是一个报文一个报文发给应用层的。
TCP异常 进程终止这种情况会释放文件描述符依旧可以发送FYN。 机器重启这种情况下类似于进程终止。 机器断开电源/拔网线这种情况下如果有写入操作接收端会发现连接不在了就会reset并且TCP内部也有定时器定时询问连接是否存在。
TCP小结
可靠性
校验和序号确认应答超时重传连接管理流量控制拥塞控制
提高性能
滑动窗口快速重传延迟应答捎带应答
基于TCP的应用层协议
HTTPHTTPSSSHTelnetFTPSMTP
TCP与UDP对比 其实二者并无优劣之分只是需要根据不同的应用场景来使用不同的协议。
TCP适用于可靠传输的场景而UDP适用于高速传输和对实时性要求高的场景。
Listen函数的第二个参数 第二个参数backlog实际上是为上层维护的链接队列的长度这个长度不可没有也不可太长。 我们将gbacklog设为2然后注释掉accept。 然后用四个客户端来连接这个服务器然后使用netstat命令查看服务器连接情况。 我们发现连接队列中只有三个连接是被维护着的也就是全连接状态还有一个连接从服务器角度来看还在SYN_RECV中也就是所谓的半连接状态。 这样backlog的含义就知道了它是指服务器维护的全连接队列的长度长度为backlog 1. 如果服务器一直未accept或者说服务器内部的链接已满还未退出那么这个全连接队列就无法accept。 全连接队列已建立连接但是未accept的链接。 总结 以上就是应用层的HTTPHTTPS的细节以及传输层UDP以及TCP详解。 了解了HTTP的报头协议格式以及方法 状态码sessioncookie还有HTTPS是如何加密的。 了解了UDP报头协议格式等。 了解了TCP报头格式如何连接实现可靠性还了解了超时重传机制确认应答机制连接管理机制序号的作用滑动窗口拥塞控制流量控制快速重传延迟应答和捎带应答。 对于网络基础有了一定的了解但是对于网络层和数据链路层我们依旧未知还是需要继续努力。