操作起来 3.23

3.23

格子量也要无量纲化

计网(参考:小林coding)

TCP断开连接 4次握手

客户端主动断开连接,发送FIN标志位为1的TCP报文,进入fin_wait_1状态,

服务器收到FIN报文,向客户端发送ACK报文,进入CLOSED_WAIT状态,

客户端收到ACK报文,进入FIN_WAIT_2状态

等待服务器处理完数据后,向客户端发送FIN报文,进入LAST_ACK状态

客户端收到FIN报文,回一个ACK报文,进入TIME_WAIT状态

服务器收到ACK报文,进入CLOSED状态,至此服务器断开连接

客户端在经过2MSL一段时间后,自动进入CLOSED状态,至此客户端也实现了连接的关闭

主动关闭连接的一方,才有TIME_WAIT状态

为什么是四次

客户端发送FIN报文,表明俺不想请求数据了,但是俺还能接受数据,服务端接收响应先回了一个ACK报文,就是说好了我知道你不想干了,等等我处理一下相关事宜再一起答复给你,嘀嘀嘀,好了我处理好了把一些数据发给你

即等到服务器不想发送数据时才发送FIN报文

总而言之服务器需要等待数据的发送与处理

为什么需要TIME_WAIT

1 防止重新建立连接时接收到旧的TCP报文

​ 可能结果:收到以前的数据,造成数据紊乱

2 防止服务器没有收到ACK报文

​ 请求建立连接时,收到RST拒绝报文

为什么TIME_WAIT需要 2 MSL(Message Segment Lifetime)

TCP基于IP,IP有一个TTL(TIME TO LIVE路由最大转发次数),MSL的值大于等于TTL,确保没收到的报文能够自然消亡。

合理的解释是一来一回需要两个报文生存时间,例如被动方没有收到ACK报文会重发FIN报文,一来一回正好2个MSL

LINUX系统中默认的是30s,可以在内核代码中更改改时间,但需要重新编译

TIME_WAIT过长的危害

1 占用内存资源

服务器监听端口,将监听到的连接丢给线程池,如果有大量TIME_WAIT时,系统资源会被占满

2 占用端口资源, 客户端有固定的端口数,被占满会导致无法建立新的连接

如何优化TIME_WAIT

三种方式:

打开net.ipv4.tcp_tw_reuse 和 net.ipv4.tcp_timestamps 选项,复用处于TIME_WAIT的socket为新连接所用

net.ipv4.tcp_max_tw_buckets,设定一个ITME_WAIT最大值,超过这个值将TIME_WAIT重置,危险!

程序中使⽤ SO_LINGER ,应⽤强制使⽤ RST 关闭。

如果已经建立了连接,但是客户端突然出现了故障怎么办

TCP有一个保活机制,tcp中长时间没有数据传输时,保活机制会发送探测报文,

保活机制包含三个参数:保活时间、保活探测的次数、保活探测的间隔

分为以下三种情况:

1 对端正常工作,收到探测报文正常响应,保活时间重置

2 对端崩溃并重启,对端可以响应,但是没有有效的连接信息,会回复一个RST报文,重置TCP连接

3 对端程序崩溃,探测报文石沉大海,再经历了保活探测次数后,该连接被报告已死亡

连接重置?

socket编程

socket是操作系统提供的api(可以进行各种通信方式,可以使用UDP,TCP等多种协议)

套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

针对TCP应该如何socket编程

流程:

服务端、客户端初始化socket,得到文件描述符

服务端调用 bind,将套接字绑定一个IP地址和端口号

服务器调用listen,进行监听

服务器调用accept,等待客户端连接

客户端调用connect,向服务端的地址和端口发起连接请求

服务端accept返回用于传输的socket文件描述符

客户端调用write写入数据,服务端调用read读取数据

客户端断开连接时,会调用close,那么服务端read读取数据的时候,会读到EOF,待处理完数据后,服务端调用close,表示连接关闭

注意,监听的socket和真正用来传数据的socket,是两个socket

listen时候参数backlog的意义

linux内核中会维护两个队列:SYN队列(未完成连接队列,SYN_RECV); Accept队列(已完成连接队列,ESTABLISHED)

应用程序会取出已经完成连接的accept队列里的socket

int listen (int socketfd, int backlog)

socketfd 文件描述符

backlog不同版本不一样:

早期是SYN队列大小,2.2之后就是ACCEPT队列长度

客户端connect返回是在二次握手之后,服务端accept返回是在第三次握手成功之后

用户端调用close后发生了什么

客户端调用close,发送FIN包,进入FIN_WAIT_1

服务器接收到FIN包,TCP协议栈会为FIN包插入⼀个⽂件结束符 EOF 到接收缓冲区中,应⽤程序 可以通过 read 调⽤来感知这个 FIN 包。这个 EOF 会被放在已排队等候的其他已接收的数据之后,这就 意味着服务端需要处理这种异常情况,因为 EOF 表示在该连接上再⽆额外数据到达。此时,服务端进⼊ CLOSE_WAIT 状态; 接着,当处理完数据后,⾃然就会读到 EOF ,于是也调⽤ close 关闭它的套接字,这会使得服务器会发 出⼀个 FIN 包,之后处于 LAST_ACK 状态;

客户端接收到服务端的 FIN 包,并发送 ACK 确认包给服务端,此时客户端将进⼊ TIME_WAIT 状态; 服务端收到 ACK 确认包后,就进⼊了最后的 CLOSE 状态

客户端经过 2MSL 时间之后,也进⼊ CLOSE 状态;

Leetcode

递增子序列

class Solution {
public:
//需要判断是不是递增好家伙
/*可以对数组最后一个数字比较,因为没排序,所以不能用i > index nums[i] == nums[i-1]去重*/
//!path.empty() && nums[i] < path.back()
    vector<vector<int>>ans;
    vector<int>path;
  
    void bt(vector<int>& nums, int index){
        unordered_set<int>set;
        if(path.size() > 1){
            ans.push_back(path);
        }
        for(int i = index; i < nums.size(); i++){
            if((!path.empty() && nums[i] < path.back()) || set.find(nums[i]) != set.end()) continue;
            path.push_back(nums[i]);
            set.insert(nums[i]);
            bt(nums, i+1);
            path.pop_back();
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        bt(nums, 0);
        return ans;
    }
};

全排列

给个数组标记一下

class Solution {
public:
/*忘啦,*/
    vector<vector<int>>ans;
    vector<int>path;

    void bt(vector<int>& nums, vector<bool>& condi){
        if(path.size() == nums.size()){
            ans.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); i++){
            if(!condi[i]){
                path.push_back(nums[i]);
                condi[i] = true;
                bt(nums, condi);
                path.pop_back();
                condi[i] = false;
            }
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<bool>condi(nums.size(), false);
        bt(nums, condi);
        return ans;
    }
};

全排列2

两个数组访问版本,效率低

class Solution {
public:
    vector<vector<int>>ans;
    vector<int>path;

    void bt(vector<int>& nums, vector<bool>& condi){
        unordered_set<int>uset;
        if(path.size() == nums.size()){
            ans.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); i++){
            if(condi[i] || uset.find(nums[i]) != uset.end()){
                continue;
            }
            path.push_back(nums[i]);
            uset.insert(nums[i]);
            condi[i] = true;
            bt(nums, condi);
            path.pop_back();
            condi[i] = false;
        }
    }

    vector<vector<int>> permuteUnique(vector<int>& nums) {
        vector<bool>condi(nums.size(), false);
        bt(nums, condi);
        return ans;
    }
};

所以不能排序时,用哈希表

能排序时,bool数组就可以啦

改进版:

class Solution {
public:
    vector<vector<int>>ans;
    vector<int>path;

    void bt(vector<int>& nums, vector<bool>& condi){
        if(path.size() == nums.size()){
            ans.push_back(path);
            return;
        }
        for(int i = 0; i < nums.size(); i++){
            if(condi[i] || (i > 0 && nums[i] == nums[i-1] && !condi[i-1])){
                continue;
            }
            path.push_back(nums[i]);
            condi[i] = true;
            bt(nums, condi);
            path.pop_back();
            condi[i] = false;
        }
    }

    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<bool>condi(nums.size(), false);
        bt(nums, condi);
        return ans;
    }
};

操作系统

进程

运行中的程序,代码写在硬盘里,运行代码时先将他加载到内存中,这和看的讲的内存金字塔结构相呼应

并发,单核交替执行多个程序;并行:多核同时执行多个程序

进程状态:运行态、阻塞态、就绪态

阻塞态不能直接到运行态,就绪态似乎也不能到阻塞态

再加两个:创建态、结束态

阻塞态通常被换出到硬盘,再次运行时再加载到内存

所以又可以加两种了:

阻塞挂起,进程在外存等待事件出现; 就绪挂起:进程在外存,只要进入内存就可以运行

可以通过sleep或ctrl+z命令挂起进程

进程的控制结构

PCB, 进程存在的唯一标识。链表欸,next指针连起来就好了咩

组成

进程基本信息:进程标识符、用户标识符

进程控制和管理信息:进程状态、进程抢占CPU优先级

资源分配清单:虚拟地址空间、所打开的文件列表以及所使用的I/O设备

CPU相关信息:相关寄存器的值

管理

链表:就绪队列、阻塞队列。方便插入和删除

索引:相对麻烦一点

其他

格子单位也需要无量纲化,无量纲化为1、1

思考一下马赫数为什么会随着补偿而改变呢。声速不变,格子速度会变是吧,那么为了和其他尺度相同,是不是应该固定格子速度,这个需要公式推导一下

写小作文哈哈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值