实际上,上网的大部分行为都是在进行进程间通信.. 也就是不断地获取信息和发送信息
比如:
1. 把服务器上面地资源数据拿到本地 (短视频, 网页)
2. 把本地地数据推送到服务器 (搜索, 注册,登录,下单)
http的底层一般是基于传输层协议tcp实现的
http是超文本传输协议, 在底层实现中涉及了很多地文本解析
再谈http地无状态: 指协议不具备记忆地能力, 不需要对于进程间通信地历史状态进行保存, 服务器是无法判断用户是否历史上曾经打开过这个网页了的. 也就是上一次打开网页和这一次打开相同的网页互相不关联, 也不知道你上次打开过. (不会记忆)这个就叫做无状态
request 报文
response 报文
主要请求方法解释:
上述便是需要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 : 端口号 可以访问, 服务器可能没有开放端口, 可以在购买的服务器安全组中设置
相关视频推荐
《tcp/ip详解卷一》: 150行代码拉开协议栈实现的篇章
网络原理tcp/udp,网络编程epoll/reactor,面试中正经“八股文”
通过10道经典网络面试题,搞懂tcp/ip协议栈所有知识点
学习地址: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
为啥叫做HTTPS , S的含义, SSL:加密,在HTTP下加入SSL层 (解决上述问题)
SSL操作步骤:
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位标志位:
16位窗口大小(先留个疑,其实就是存储接收缓冲区还剩下的大小, 和流量控制有关)
16位校验和: 发送端填充, CRC校验. 接收端校验不通过, 则认为数据有问题. 此处的检验和不光包含TCP首部, 也 包含TCP数据部分
6位紧急指针: 标识哪部分数据是紧急数据
tcp连接建立之后是存在接收和发送内核缓冲区的....
send 还有 recv这些接口都不是直接将数据发送到网路中,也不是直接从网路中读取数据的...
而是存在发送缓冲区和接收缓冲区的概念, 这些都是内核缓冲区。。。同样之前的窗口大小其实就是接收缓冲区还剩余的大小, 支持流量控制 (你发送的数据不能超过,不然就满了)
接收缓冲区大写也对应着流量控制:why? 如何理解
接收端处理数据的速度是有限的. 如果发送端发的太快, 导致接收端的缓冲区被打满, 这个时候如果发送端继续发送, 就会造成丢包, 继而引起丢包重传等等一系列连锁反应.
因此TCP支持根据接收端的处理能力, 来决定发送端的发送速度. 这个机制就叫做流量控制(Flow Control)
所以窗口大小就是接收端处理能力的代表 (发送端接收到窗口大小会根据窗口大小进行调节自己的发送速度,进行流量控制) 填充窗口字段就是填充的自身的接收缓冲区中剩余空间的大小 (此窗口也称为接收窗口)
窗口大小字段越大, 说明网络的吞吐量越高;
ACK应答的含义就是: acknum 之前的序号的数据包我都已经收到了,下一次你从acknum开始发送吧
超时重发指的是因为网络环境的拥堵阻塞导致了在很长一段时间发送方都没有等到自己之前发送包的回音 (于是TCP默认是丢包)然后会采取重传措施
由于重传机制,会存在一些情况是 之前因为网络拥堵的数据包 在网络环境恢复之后正常传入到对端, 导致对端可能会收到多份重复的数据报文,不过嘞因为序号的存在可以通过需要进行简单的去重即可
但是这个超时时间如何确认??? 多少算合适,这个也是个置得讨论的问题
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可靠传输的学习: