实际上,上网的大部分行为都是在进行进程间通信.. 也就是不断地获取信息和发送信息
比如:
1. 把服务器上面地资源数据拿到本地 (短视频, 网页)
2. 把本地地数据推送到服务器 (搜索, 注册,登录,下单)
http的底层一般是基于传输层协议tcp实现的
浏览器和web服务器三次握手建立TCP连接浏览器进行 req (request请求)服务器进行 rep (reply响应)浏览器和web服务器四次挥手断开TCP连接http是超文本传输协议, 在底层实现中涉及了很多地文本解析
再谈http地无状态: 指协议不具备记忆地能力, 不需要对于进程间通信地历史状态进行保存, 服务器是无法判断用户是否历史上曾经打开过这个网页了的. 也就是上一次打开网页和这一次打开相同的网页互相不关联, 也不知道你上次打开过. (不会记忆)这个就叫做无状态
request 报文
response 报文
主要请求方法解释:
GET : 直接获取对应的资源信息(eg: 网页) 资源从哪来 URL定位POST : 将数据交给服务器, 通过正文提交, 不需要URL定位上述便是需要Content-Length的原因, 获知正文是否存在以及正文长度
再次手写一个便理解的简单的httpserver.cc 的服务器, 使用C++完成
#include #include #include #include #include #include #include #include #include #define ERR_EXIT(m) \do { std::cerr << m << std::endl; close(EXIT_FAILURE); } while(0)typedef struct sockaddr SA; int main() {signal(SIGCHLD, SIG_IGN);//信号处理, 避免子进程僵尸int listenfd, connfd, pid;socklen_t addLen;struct sockaddr_in clientAdd, serveAdd;if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ) {ERR_EXIT("socket");} int flag = 1; setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); //SO_REUSEADDR BOOL 允许套接口和一个已在使用中的地址捆绑(参见bind()) //SOL_SOCKET固定level设置bzero(&serveAdd, sizeof(serveAdd));//清空serveAdd.sin_family = AF_INET;//协议家族serveAdd.sin_port = htons(8080);//默认80端口serveAdd.sin_addr.s_addr = htonl(INADDR_ANY);//INADDR_ANY == 0 作用适配地址if (bind(listenfd, (SA*)&serveAdd, sizeof(serveAdd)) == -1) {ERR_EXIT("bind");}//3: 等待队列syn队列的长度if (listen(listenfd, 3) == -1) {ERR_EXIT("listen");}while (1) {if ((connfd = accept(listenfd, (SA*)&clientAdd, &addLen)) == -1) {ERR_EXIT("accept");}pid = fork();//fork出来子进程if (pid) {close(connfd);//父进程关闭connfd然后仅仅进行listen. SIGCHLD会自动收尸} else {close(listenfd);//子进程进行发送响应报文char buffer[1024]; recv(connfd, buffer, sizeof(buffer), 0); std::cout << "#############################http request begin#############################################"< 服务器IP : 端口号 可以访问, 服务器可能没有开放端口, 可以在购买的服务器安全组中设置
再次图解小结HTTP, 整个协议栈的角度去看相关视频推荐
《tcp/ip详解卷一》: 150行代码拉开协议栈实现的篇章
网络原理tcp/udp,网络编程epoll/reactor,面试中正经“八股文”
学习地址:C/C++Linux服务器开发/后台架构师【零声教育】-学习视频教程-腾讯课堂
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
HTTPS : 是以安全为目标的HTTP通道, 通俗说就是安全版本的HTTP,
为啥需要HTTPS
HTTP的请求信息是明文传输, 容易被窃取HTTP不会验证对方的信息, 存在被冒充的风险数据的完整性没有校验, 容易被中间人篡改为啥叫做HTTPS , S的含义, SSL:加密,在HTTP下加入SSL层 (解决上述问题)
SSL操作步骤:
验证服务器端允许客户端和服务端选择加密算法和密码, 确保双方都支持验证客户端使用公钥加密技术来生成共享加密数据创建一个加密的SSL连接基于该SSL连接传递HTTP请求HTTPS的主要作用:一个是建立一个信息安全通道,用来保证数据传输的安全性,另外一个就是验证网站的真实性了...
写传输层协议之前先介绍一个四元组的概念: 网络通信的实现就是基于四元组的,不论是TCP还是UDP 要想将数据从一端传入到另外一端,就必须明确对端的二元组, 双方如果都要相互通信就要确定四元组
首先我们确定要双方不同主机上的不同进程间进行通信, 必须确定双方的 ip + port why?
上述图主要是为了引出为啥要 ip
上述图是为了引出为啥需要 port
报文分析
源 / 目的端口,那就是老身常谈了, 从哪个进程来,到哪个进程去
32位序号和确认序号 (原谅咱留个小疑惑,后面解释,和重传机制有关系)
4位TCP报头长度: 表示该TCP头部有多少个32位bit(有多少个4字节); 所以TCP头部最大长度是15 * 4 = 60 (基本衡量单位都是4字节为最小单位) 因为首部长度是4位 最大就是15; 所以最大首部长度就是 15 * 4 (最小单位) = 60字节
6位标志位:
URG: 紧急指针是否有效ACK: 确认号是否有效PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段SYN: 请求建立连接; 我们把携带SYN标识的称为同步报文段FIN: 通知对方, 本端要关闭了, 我们称携带FIN标识的为结束报文段16位窗口大小(先留个疑,其实就是存储接收缓冲区还剩下的大小, 和流量控制有关)
16位校验和: 发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也 包含TCP数据部分
6位紧急指针: 标识哪部分数据是紧急数据
tcp连接建立之后是存在接收和发送内核缓冲区的....
send 还有 recv这些接口都不是直接将数据发送到网路中,也不是直接从网路中读取数据的...
而是存在发送缓冲区和接收缓冲区的概念, 这些都是内核缓冲区。。。同样之前的窗口大小其实就是接收缓冲区还剩余的大小, 支持流量控制 (你发送的数据不能超过,不然就满了)
接收缓冲区大写也对应着流量控制:why? 如何理解
接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应.
因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control)
所以窗口大小就是接收端处理能力的代表 (发送端接收到窗口大小会根据窗口大小进行调节自己的发送速度,进行流量控制) 填充窗口字段就是填充的自身的接收缓冲区中剩余空间的大小 (此窗口也称为接收窗口)
窗口大小字段越大, 说明网络的吞吐量越高;
ACK应答的含义就是: acknum 之前的序号的数据包我都已经收到了,下一次你从acknum开始发送吧
超时重发指的是因为网络环境的拥堵阻塞导致了在很长一段时间发送方都没有等到自己之前发送包的回音 (于是TCP默认是丢包)然后会采取重传措施
由于重传机制,会存在一些情况是 之前因为网络拥堵的数据包 在网络环境恢复之后正常传入到对端, 导致对端可能会收到多份重复的数据报文,不过嘞因为序号的存在可以通过需要进行简单的去重即可
但是这个超时时间如何确认??? 多少算合适,这个也是个置得讨论的问题
最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回".但是这个时间的长短, 随着网络环境的不同, 是有差异的.如果超时时间设的太长, 会影响整体的重传效率;如果超时时间设的太短, 有可能会频繁发送重复的包;TCP为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间.(抓核心主题,据网络环境而生 超时时间)
Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时 时间都是500ms的整数倍.如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.累计到一定的重传次数, TCP认为网络或者对端主机出现异常, 强制关闭连接.第一种是ACK丢失
如上述情况下,滑动窗口的ACK部分丢失其实不是很紧要,因为可以通过后序的ACK确认;ACK一旦确认之后代表的含义是 默认之前的所有序列数据都已经全部收到了
情况2是数据包传过去的时候就丢失了
单独解释一下 快重传 : 就是说在接收方收到一个失序的报文段的时候就立即会发出重复确认。(目的在于使得发送方尽早地知道说自己有报文丢失了,没有到达对面)接收方地意思就是 哥你确定你发的是对的,我前面的报文都还没收到 (顺序不对呀)三次之后发送方反应过来直接重传,不再等待超时
TCP是面向连接的,可靠的,基于字节流的传输层通信协议
如何保证可靠性:
性能提升上面:
1. 采取了滑动窗口
2. 快速重传 (不需要等待超时,三次对端提醒之后自动重传)
基于TCP应用层协议 HTTP HTTPS SSH Telnet FTP SMTP
先从报文分析入手
UDP的特征: 什么是无连接,不可靠,关键为什么它如此的不稳定但是在现在的短视频 音视频通话 DNS ARP这些全部都还使用的是UDP作为传输层协议
首先是无连接, 连接是什么: 连接算是一端到另外一端的不存在的一根线 (抽象的来说,这个是我的个人理解, 连接的过程也就是三次握手的过程)对于三次握手不理解的可以看我前文链接存在详解
首先不论是有连接还是无连接, 我们核心应该确定的是什么? 确定四元组,对了四元组,无连接也可以进程间通信,只不过每一次必须传入四元组, 但是口说无凭, 咱看看接口呗。对比一下:
为什么UDP是不可靠连接?
因为UDP没有TCP的哪些为了保证可靠性的机制: 比如超时重传机制,拥塞控制,流量控制机制,为数据包编号排序等...
思考为啥UDP如此不可靠我们还必须要使用它, 而且还会尽量的使其变得可靠, 还要专门做UDP可靠性设计,这个不是多次一举吗. 不如直接使用TCP?
首先解释UDP相比TCP为什么相对实时性好, 在时间上更短, 更加快速。。。
以上是从不必要的三次握手建立连接上解释这个速度问题, 为啥UDP更快
而且在进行数据传输的时候TCP还会存在一定的时间限制,时间阈值,超过这个时间就需要进行重传, 重传也会导致延迟性,向我们的qq聊天呀就经常出现这样的延迟现象,很明显底层应当是采取的TCP作为传输层协议.
根据上述的延迟解释一下音视频通话为例解释下为啥使用UDP而不是TCP?
一句话解释:就是通话延迟的问题,我们qq上发个消息是无所谓,延迟下我们可以等会看嘛,但是你在跟别人搞音视频,像抖音这些,或者各种视频,这个要是通话延迟,几秒前说的话几秒后出来了你这个还搞个屁呀, 还说得清嘛,这个很明显需要实时通话,正是这样的场景存在所以UDP必然是需要的。。。而且现在音视频(短视频)如此火爆更是少不了UDP了
我们再从另外一个角度来分析一下这个问题, 服务端压力上面来考虑。。。
现有的udp可靠传输协议就是KCP了,感兴趣的还真有必要得去深入研究一下,我个人是研究深度还不够,先暂且浅显的聊一聊这个UDP可靠传输设计的一些基本的东西,KCP要是将来我的理解深入足够会尽力刨析一下...
首先既然提到了MTU 先解释一下 MTU是个啥玩也.
总结UDP可靠传输的学习:
多研究TCP协议的实现设计 udp可靠传输,和TCP不一样,重传策略受到我们的控制可控 (也不一定所有都需要重传) 像音视频,游戏走位 超时太久丢包就丢了,不需要重传... 但是有些其他应用场景下又必须进行重传重传时机的确定 (根据具体的业务需求去设计,不要一味追求设计一个通用性的UDP可靠传输协议)版权声明:我们致力于保护作者版权,注重分享,被刊用文章【网络合同(再谈Http和Https及TCP)】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理!;
工作时间:8:00-18:00
客服电话
电子邮件
beimuxi@protonmail.com
扫码二维码
获取最新动态
