目录
一、TCP的可靠性
TCP的可靠性体现在检验和、确认应答、超时重传、最大消息长度、滑动窗口、拥塞控制等
1.检验和
通过检验和的方式,接收端可以检验出数据是否出现差错和异常,在TCP首部加上12字节的伪首部,检验和要计算三部分:TCP首部、TCP数据、TCP伪首部。
2.确认应答
当一方发送了请求,另一方必须有确认应答包,如果没有收到确认应答ACK就会重新发送。
3.超时重传
一般发送请求和接收应答的传输时间总和称为一个RTT,有时还会因为网络中的其他原因(抖动)让这段时间延长。超时重传的时间是比RTT+抖动的时间还要长。
如果一个包在发送请求后经过规定的时间后仍然没有收到确认应答就会超时重传。
如果一个包多次重传仍然未收到确认应答,那么认为接收端异常,强制关闭连接。
4.最大消息长度
TCP建立连接时,双发都会规定一个最大消息长度作为每次发送的单位,超时重传也是这个长度。原则上这个最大消息长度刚好不被网络层分块。
5.滑动窗口
TCP的超时重传虽然能够防止丢包,但是每次的等待时间会让传输效率低下。滑动窗口就是在不等待确认包的前提下发送下一个请求包。窗口的大小就是在等待确认包的时间中能传输的最大数据量。
①不等待确认包,怎样保证请求已经发送给了接收方呢?
这种机制使用了大量的缓冲区,发送的请求数据存放在缓冲区中,只要接收到了确认应答,就在缓冲区中将对应的请求数据删除。
②接收方未收到想要的请求数据会怎么样?
接收方如果一直收不到想要的数据,就会对之前的数据进行确认并且发送3次重复的确认应答,发送方就会认为是丢包了并且重新发送。
6.拥塞控制
滑动窗口解决了网络速率不一致产生的丢包问题,但是网络拥堵条件下不断发送数据会加重网络负担,拥塞控制就是在开始时先发送少量的数据,再决定按照多大的速度传输数据。
拥塞避免分为两个阶段:
①慢开始:开始时定义拥塞控制为1,之后每次收到确认应答就按指数倍扩大拥塞窗口。
②拥塞避免:当到达默认的阈值时,每次拥塞窗口+1。
③当到达网络拥塞时,重新定义的阈值变为原来的一半,拥塞窗口从1开始执行上面两个阶段。
二、层序遍历的实现
层序遍历:从根节点出发,从上到下从左到右依次输出。
1.自顶向下
题目链接:102. 二叉树的层序遍历 - 力扣(LeetCode)
解题思路:
①因为结果要求输出集合,所以我们首先创建一个可以存放所有结果的集合和一个存放每层元素的集合。
②将根节点放入队列中,每次队列不为空就取队列的第一个元素,判断左子树和右子树是否存在,如果存在就放入队列中,将结果放入每层的集合中。
③队列为空就说明遍历完了,最后将每层的集合放入最后的结果集合中。
采用递归的思想来完成。
代码展示:
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if(root == null){
return result;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
List<Integer> level = new ArrayList<>();
int size = queue.size();
while(size>0){
TreeNode node = queue.poll();
level.add(node.val);
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
size--;
}
result.add(level);
}
return result;
}
}
2.自底向上
题目链接:107. 二叉树的层序遍历 II - 力扣(LeetCode)
解题思路:
这里需要知道链表的一个方法addFirst(),这个方法是每次都将数据放进链表前面(头插法的底层实现)。那么这道题和上道题也就没什么不一样了。
具体的思路还是上面的,唯一区别是存放结果的集合变成了链表结构,将每层的集合加入结果集合时使用addFirst()即可。
代码展示:
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
LinkedList<List<Integer>> result = new LinkedList<>();
if(root == null){
return result;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(!queue.isEmpty()){
List<Integer> level = new ArrayList<>();
int size = queue.size();
while(size>0){
TreeNode node = queue.poll();
level.add(node.val);
if(node.left!=null){
queue.offer(node.left);
}
if(node.right!=null){
queue.offer(node.right);
}
size--;
}
result.addFirst(level);
}
return result;
}
}
三、Linux常用命令
1.文件管理
ls/ll:显示当前目录文件(ls只是显示显示文件、ll会展示出来隐藏的文件)
cd+路径:切换到当前工作目录
touch:创建普通文件
mkdir:创建目录文件
rm:删除普通文件 (-r表示递归 -f不显示任何信息,不会提示确认信息)
rmdir:删除目录文件
mv:剪切移动
cp:拷贝
chmod:修改文件权限
chown:修改文件属主
find:查找文件 (查找范围大耗时长)
pwd:显示当前工作目录的绝对路径
vim:文本编译器
whereis+命令:搜索命令的目录
cat:显示整个文件的内容
more:让日志分页显示,同时显示内容的百分比,更方便阅读。(-num 一次显示的行数、+num 从第 num 行开始显示)
less:less的查找功能更强大,通常作为管道过滤信息。
2.进程管理
ps:显示进程信息(-e显示所有进程)
kill pid:结束进程(kill -9 pid:强制结束进程、-1 重新加载进程、-15 正常关闭进程、-stop 挂起进程)
jobs:显示后台挂起进程
pstree:树状显示进程
3.系统管理
top:动态显示进程信息和系统运行统计信息
free:显示系统运行的信息(内存、缓存.....)
mpstat:处理器的使用情况
vmstat:系统各个资源的使用情况
4.网络通讯命令
ping:测试网络连通性
ifconfig:配置网络设备
netstat:显示网络相关信息(各种连接、路由表信息、网卡接口信息,常常用来显示tcp连接及状态)
service:管理系统运行的服务器
mail:查看发送电子邮件
write:给用户发送信息