C++ Linux Web Server 面试基础篇-计网
Posted 忆_恒心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ Linux Web Server 面试基础篇-计网相关的知识,希望对你有一定的参考价值。
⭐️我叫忆_恒心,一名喜欢书写博客的在读研究生👨🎓。
如果觉得本文能帮到您,麻烦点个赞
👍呗!
近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧,喜欢的小伙伴给个三连支持一下呗。👍⭐️❤️
Qt5.9专栏
定期更新Qt的一些项目Demo
项目与比赛专栏
定期更新比赛的一些心得,面试项目常被问到的知识点。
Linux Web Server
项目虽然是现在C++求职者的人手一个的项目,但是想要吃透这个项目,还是需要一定的基础的,以项目为导向,进行基础的学习。
涵盖了计算机网络(网络编程)
常见的知识点和常见的操作系统知识
。
博主参加过大大小小的互联网厂和银行的秋招和春招的笔试与面试,整理了下面的2万7千字的长文(😄都是干货,写作不易啊),喜欢,觉得有帮助的,欢迎订阅专栏,后续有很多优质的文章进行更新,有任何疑问,欢迎留言!
面试基础篇-计网 一
1、说一下TCP三次握手的过程
- 初始状态:客户端处于
closed(关闭)
状态,服务器处于listen(监听)
状态。 - 第一次握手:客户端发送请求报文将
SYN = 1
同步序列号和初始化序列号seq = x
发送给服务端,发送完之后客户端处于SYN_Send
状态。(验证了客户端的发送能力和服务端的接收能力) - 第二次握手:服务端收到
SYN
请求报文之后,如果同意连接,会以自己的同步序列号SYN(服务端) = 1
、初始化序列号seq = y
和确认序列号(期望下次收到的数据包)ack = x+ 1
以及确认号ACK = 1
报文作为应答,服务器为SYN_Receive
状态。 - 第三次握手: 客户端接收到服务端的
SYN + ACK
之后,知道可以下次可以发送了下一序列的数据包了,然后发送确认序列号ack = y + 1
和数据包的序列号seq = x + 1
以及确认号ACK = 1
确认包作为应答,客户端转为established
状态。(分别站在双方的角度上思考,各自ok)
2、三次握手的必要性
第三次握手主要为了防止已失效的连接请求报文段突然又传输到了服务端,导致产生问题。
- 比如客户端A发出连接请求,可能因为网络阻塞原因,A没有收到确认报文,于是A再重传一次连接请求。
- 连接成功,等待数据传输完毕后,就释放了连接。
- 然后A发出的第一个连接请求等到连接释放以后的某个时间才到达服务端B,此时B误认为A又发出一次新的连接请求,于是就向A发出确认报文段。
- 如果不采用三次握手,只要B发出确认,就建立新的连接了,此时A不会响应B的确认且不发送数据,则B一直等待A发送数据,浪费资源。
3、四次挥手的过程
- A的应用进程先向其TCP发出连接释放报文段(
FIN=1,seq=u
),并停止再发送数据,主动关闭TCP连接,进入FIN-WAIT-1
(终止等待1)状态,等待B的确认。 - B收到连接释放报文段后即发出确认报文段(
ACK=1,ack=u+1,seq=v
),B进入CLOSE-WAIT
(关闭等待)状态,此时的TCP处于半关闭状态,A到B的连接释放。 - A收到B的确认后,进入
FIN-WAIT-2
(终止等待2)状态,等待B发出的连接释放报文段。 - B发送完数据,就会发出连接释放报文段(
FIN=1,ACK=1,seq=w,ack=u+1
),B进入LAST-ACK
(最后确认)状态,等待A的确认。 - A收到B的连接释放报文段后,对此发出确认报文段(
ACK=1,seq=u+1,ack=w+1
),A进入TIME-WAIT
(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL
(最大报文段生存时间)后,A才进入CLOSED
状态。B收到A发出的确认报文段后关闭连接,若没收到A发出的确认报文段,B就会重传连接释放报文段。
4、四次挥手的必要性
因为当Server端收到Client端的SYN
连接请求报文后,可以直接发送SYN+ACK
报文。但是在关闭连接时,当Server端收到Client端发出的连接释放报文时,很可能并不会立即关闭SOCKET,所以Server端先回复一个ACK
报文,告诉Client端我收到你的连接释放报文了。只有等到Server端所有的报文都发送完了,这时Server端才能发送连接释放报文,之后两边才会真正的断开连接。故需要四次挥手。
5、第四次挥手为什么要等待2MSL?
- 保证A发送的最后一个ACK报文段能够到达B。这个
ACK
报文段有可能丢失,B收不到这个确认报文,就会超时重传连接释放报文段,然后A可以在2MSL
时间内收到这个重传的连接释放报文段,接着A重传一次确认,重新启动2MSL计时器,最后A和B都进入到CLOSED
状态,若A在TIME-WAIT
状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到B重传的连接释放报文段,所以不会再发送一次确认报文段,B就无法正常进入到CLOSED
状态。 - 防止已失效的连接请求报文段出现在本连接中。A在发送完最后一个
ACK
报文段后,再经过2MSL,就可以使这个连接所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现旧的连接请求报文段。
6、UDP通信的时候丢包情况如何避免?
比如向我们现在这样通话,假设出现丢包的情况,应该如何处理
没有考虑过
参考答案:
UDP通信—收包率低/丢包率高的
原因:
(1)缓存太小,不能及时接收数据
连续多个UDP包超过了UDP缓冲区大小,比如
1、UDP包过大
2、UDP发包速率过快,突发大数据流量超过了缓冲区上限
(2)recvfrom()
接收到数据之后处理速度太慢
如果数据接收和处理是连续进行的,那么可能由于数据处理过慢,两次recvfrom()
调用的时间间隔发过来的包丢失
解决办法
- UDP包过大
解决办法:增加系统发送或接收缓冲区大小
int nBuf = 32 * 1024
setsockopt(s,SOL_SOCKET, SO_RCVBUF, (const char*)&nBuf, sizeof(int));
setsockopt(s,SOL_SOCKET, SO_SNDBUF, (const char*)&nBuf ,sizeof(int))
- 发包速率太快
解决办法:增加一个应答机制,处理完一个包后,在继续发包
recvfrom()
接收到数据之后处理速度太慢
服务器程序启动之后,开辟两个线程,一个线程专门用于接受数据包,并存放在应用层的缓冲区;另外一个线程用于专门处理和相应数据包请求,避免因为处理数据造成数据丢失。本质上还是增大了缓冲区大小,只是将系统的缓冲区移动到了自己的缓冲区。
- 最复杂的方式
在应用层实现丢包重发机制和超时机制,确保数据包不丢失。
什么是TCP粘包/拆包?发生的原因?
一个完整的业务可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这个就是TCP的拆包和粘包问题。
原因
1、应用程序写入数据的字节大小大于套接字发送缓冲区的大小.
2、进行MSS大小的TCP分段。( MSS(网络传输最大值)=TCP报文段长度-TCP首部长度)
3、以太网的payload大于MTU进行IP分片。( MTU指:一种通信协议的某一层上面所能通过的最大数据包大小。)
解决方案
1、消息定长。
2、在包尾部增加回车或者空格符等特殊字符进行分割
3、将消息分为消息头和消息尾。
4、使用其它复杂的协议,如RTMP(实时信息传输协议)协议等。
TCP粘包、拆包及解决办法
为什么常说 TCP 有粘包和拆包的问题而不说 UDP ?
由前两节可知,UDP 是基于报文发送的,UDP首部采用了 16bit 来指示 UDP 数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。
而 TCP 是基于字节流的,虽然应用层和 TCP 传输层之间的数据交互是大小不等的数据块,但是 TCP 并没有把这些数据块区分边界,仅仅是一连串没有结构的字节流;另外从 TCP 的帧结构也可以看出,在 TCP 的首部没有表示数据长度的字段,基于上面两点,在使用 TCP 传输数据时,才有粘包或者拆包现象发生的可能。
为什么会发生 TCP 粘包、拆包?
- 要发送的数据大于 TCP 发送缓冲区剩余空间大小,将会发生拆包。
- 待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。
- 要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。
- 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
粘包、拆包解决办法
由于 TCP 本身是面向字节流的,无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,归纳如下:
- **消息定长:**发送端将每个数据包封装为固定长度(不够的可以通过补 0 填充),这样接收端每次接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
- **设置消息边界:**服务端从网络流中按消息边界分离出消息内容。在包尾增加回车换行符进行分割,例如 FTP 协议。
- **将消息分为消息头和消息体:**消息头中包含表示消息总长度(或者消息体长度)的字段。
- 更复杂的应用层协议比如 Netty 中实现的一些协议都对粘包、拆包做了很好的处理。
参考资料:
计算机网络的部分图片:https://interviewguide.cn/
最后,最后
如果觉得有用,麻烦三连👍⭐️❤️支持一下呀,希望这篇文章可以帮到你,你的点赞是我持续更新的动力
Linux - Ubuntu Server基础
Ubuntu Server:部署环境,用来部署项目的server系统。
XShell:用来连接linux的工具。web项目要部署到远程服务器上,所以需要XShell来连接远程服务器。
pycharm:开发工具(专业版对于web开发更友好)
python3:编程语言。
安装方法一:直接用别人打包好的ova
已有大神为我做好了oav文件,里面包含了mysql, redis, mongodb, python3.5。
本人使用VMware。安装VMware后,会自动关联该文件,直接双击oav文件就行。
安装途中需要输入两次:bash install.sh
第一次执行配置网络,完了系统会自动重启。第二次执行就是正常安装了。
(bash命令:执行一些脚本文件的命令)
安装方式二:自己安装
至于选择哪一个发行版做server(需要自己搞定上网问题)
我自己选择了Ubuntu Server 16 LTS作为入门。后来升级了系统,但出现了很多问题。然后把这个干掉,重新装了最新版。
(一).镜像下载完后,我选择用VMWare安装。VMWare为我们会进行简易安装,很方便的。就是自己设置好喜欢的用户名和密码即可。注:ubuntu18.04 LTS的安装界面有很大的变化,得自己一步一步设置。
(1).提示1:系统装完,先升级apt,不然你很多插件都装不上!命令:sudo apt update 然后 sudo apt upgrade
(2).提示2:新的系统,肯定有很多程序没有安装过,执行命令的时候,如果没有这个程序,ubuntu server会有对应的提示。直接提示了安装的命令,照着敲就可以了。
(3).查看当前系统的版本:sudo lsb_release -a
(二).XShell连接虚拟机
(1).本人安装了2018发布的python3.7.0
# 先安装依赖。避免 ModuleNotFoundError No module named "_ctypes" 这个错误 sudo apt-get update sudo apt-get upgrade sudo apt-get dist-upgrade sudo apt-get install build-essential python-dev python-setuptools python-pip python-smbus sudo apt-get install libncursesw5-dev libgdbm-dev libc6-dev sudo apt-get install zlib1g-dev libsqlite3-dev tk-dev sudo apt-get install libssl-dev openssl sudo apt-get install libffi-dev # 开始安装 # 实现准备好源码包 tar -xvf Python-3.7.0.tgz cd Python-3.7.0 ./configure make sudo make altinstall
(2).从国内的源,安装模块
例如安装虚拟环境:sudo pip3 install -i https://pypi.douban.com/simple virtualenv
(四).安装MySQL
https://www.linuxidc.com/Linux/2017-05/143864.htm
注意事项:装完MySQL后,如果不能 mysql -u root -p 被拒绝了,执行下面的代码:
sudo mysql -u root use mysql; mysql> update user set plugin=\'mysql_native_password\' where User=\'root\'; flush privileges;
(五).安装Redis
(1).先 sudo apt update
(2).然后输入命令:sudo apt install redis-server,进行直接安装。
(3).输入命令:redis-server,启动服务。
(4).可以使用"redis-server -v",来查看当前redis的版本。
(六).安装MongoDB
(1).直接打命令:"sudo apt install mongodb"
(2).使用"mongod --version",查看版本
(七).注意事项
(1).ubuntu系统默认是禁止root用户登录的
全局与虚拟环境:
(一).概念
首先,虚拟环境它不是虚拟机,它是在虚拟机中的一个开发环境。
虚拟机相当于一个水池,虚拟环境就是水池中的一个水桶。一个虚拟环境一个水桶,水桶与水桶之间相互独立,互不相关。
在全局中配置的python3环境,与虚拟环境也互不相关。
(二).用途
不同的项目也许用的是不用的解释器。比如,西瓜皮,它只支持python2.7。
难道会因为一个项目,而去改动全局环境吗?改不好,全局环境也崩了。
那么就建一个虚拟环境,然后在pycharm中,连接此虚拟环境中的解释器。
而其他项目,连接其他虚拟环境中的解释器。各个虚拟环境互不相关,所以也不会发生斗殴事件。
一、两个常用的虚拟机
虚拟机是什么?就是电脑系统中的一台小电脑。
VMware:
专业的虚拟机软件,非常好用!(就是吃内存厉害)
VMware11开始不再支持32位系统,VMware10是最后一个支持32位系统的版本。
特别注意:32位系统中运行"Ubuntu1604_server_32bit.oav"会有问题,需要在物理机的文件中,用记事本打开"Ubuntu1604_server_32bit.vmx",
把原本virtualhw.version="11"这一行中的"11",改成"10"。保存之后,再运行就没问题了。结果如下图:
二、两种联网模式
1.桥接:适用于wifi。和主机级别一样,就相当于再插了一根网线。
2.nat模式:相当于把物理机当成路由器,外面机子上网。
补充:virtualbox使用nat模式的话,xshell连接需要端口转发。VMware则极少需要端口转发。
端口不要随便写,避免写:80 8080 443 3389 8443,会占用!尤其是80 8080!
XShell采用SSH服务连接linux。
三、Linux基础内容
Linux稳定,而且多用户之间互不干扰。每一个用户都是在家目录下的一个文件夹。
Linux没有盘符,只有一个根目录,所有文件放在根目录下。
Linux一切皆文件,哪怕是目录,也是一个文件。
linux分区大小写!命令与参数之间要有空格!
四、Linux基础命令
(一).pwd 显示当前完整路径
(二).cd 交互目录
默认进入家(home)目录。切换根目录:cd / 切换回家目录:cd ~ 切换用户:su root 退出当前用户,回到上一个用户:exit 只要不是根目录,就是相对路径:cd 目录名称/ 上一次目录:cd -
补充:修改root密码:sudo passwd xxxxx。这个oav的root用户密码是随机的。root用户标识:#,普通用户标识:$。
(三).ls 查看
ls -a 所有文件(隐藏文件前有个点".")
ls -l 详细信息
ls -h 比较人性化
(经常是:ls -lh 出来的结果可视性特别好)
ls -S 区分大小写
(四).man 帮助
man +命令。但是cd没有帮助,是个例外。翻页:b向上,F向下,q退出
(五).tree 树状查看,看目录结构
如果报错了,就需要先安装一下:sudo apt-get install tree sudo提权(root用户不用提权)
(六).mkdir 创建目录
mkdir -p 分级创建;mkdir -v 看过程;
例1:mkdir -vp aa/bb/cc 先创建aa,再在aa下建bb,再在bb下建cc;同理删除也可以 -vp
例2:mkdir qw we er 是三个同级目录了。
(七).touch 新建文件(可被编辑的)
例:touch demo.py 注:linux中的后缀是给人看的。linux没有区分什么文件,认为都是文件。
(八).rmdir 删除空目录(如果目录下有文件,就不会删)
例1:rmdir a/b/c 删除的是c目录,因为路径精确到了"c"
(九).rm 删除文件
rm -r 分级删除
例:rm -r a 删除了整个a目录
rm -f 强制删除
例:rm -rf * 可以这样说:千万不要用!全删了!恢复linux的代价相当巨大。
(十).cat 查看,cat猫,像猫一样瞄一下。
(十一).more / less
more翻完了自动退出,less必须按Q退出。
(十二).软硬链接
软硬链接:源文件中的内容改变了,链接文件的内容也同时修改了。
不同的是源文件被删后,软链接就废了。而硬链接还是可以使用。
硬链接相当于是备份。
以上是关于C++ Linux Web Server 面试基础篇-计网的主要内容,如果未能解决你的问题,请参考以下文章