热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++面试的常见问题(二)

1.TCP三次握手四次挥手的原因为什么要进行三次握手呢(两次确认)?建立三次握手主要是因为A发送了再一次的确认,那么A为

1.TCP三次握手四次挥手的原因

为什么要进行三次握手呢(两次确认)?

建立三次握手主要是因为A发送了再一次的确认,那么A为什么会再确认一次呢,主要是为了防止已失效的连接请求报文段又突然传送给B,从而产生了错误。

所谓“已失效的连接请求报文”是这样产生的,正常情况下,A发出连接请求,但是因为连接报文请求丢失而未收到确认,于是A再重传一次连接请求,后来收到了请求,并收到了确认,建立了连接,数据传输完毕后,就释放链接,A共发送了两次连接请求报文段,其中第一个丢失,第二个到达了B,没有“已失效的连接请求报文段”,但是还有异常情况下,A发送的请求报文连接段并没有丢失,而是在某个网络节点滞留较长时间,以致延误到请求释放后的某个时间到达B,本来是一个早已失效的报文段,但是B收到了此失效连接请求报文段后,就误以为A又重新发送的连接请求报文段,并发送确认报文段给A,同意建立连接,如果没有三次握手,那么B发送确认后,连接就建立了,而此时A没有发送建立连接的请求报文段,于是不理会B的确认,也不会给B发送数据,而B却一直等待A发送数据,因此B的许多资源就浪费了,采用三次握手的方式就可以防止这种事情发生,例如刚刚,A不理会B,就不会给B发送确认,B收不到A的确认,就知道A不要求建立连接,就不会白白浪费资源。

为什么要进行四次挥手呢?

由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

在建立连接时,当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是在断开连接时,当Server端收到FIN报文时,很可能并不会立即想关闭连接,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

四次挥手的过程如下所述:

  1. 数据传输结束后,客户端的应用进程发出连接释放报文段,并停止发送数据,客户端进入FIN_WAIT_1状态,此时客户端依然可以接收服务器发送来的数据。

  2. 服务器接收到FIN后,发送一个ACK给客户端,确认序号为收到的序号+1,服务器进入CLOSE_WAIT状态。客户端收到后进入FIN_WAIT_2状态。

  3. 当服务器没有数据要发送时,服务器发送一个FIN报文,此时服务器进入LAST_ACK状态,等待客户端的确认。

  4. 客户端收到服务器的FIN报文后,给服务器发送一个ACK报文,确认序列号为收到的序号+1。此时客户端进入TIME_WAIT状态,等待2MSL(MSL:报文段最大生存时间),然后关闭连接。




2.父类和子类构造函数析构函数调用顺序

定义一个对象时先调用基类的构造函数、然后调用派生类的构造函数;

析构的时候恰好相反:先调用派生类的析构函数、然后调用基类的析构函数



3.COOKIE和session区别

COOKIE通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

1、COOKIE数据存放在客户的浏览器上,session数据放在服务器上。

简单的说,当你登录一个网站的时候,如果web服务器端使用的是session,那么所有的数据都保存在服务器上面,

客户端每次请求服务器的时候会发送 当前会话的session_id,服务器根据当前session_id判断相应的用户数据标志,以确定用户是否登录,或具有某种权限。

由于数据是存储在服务器 上面,所以你不能伪造,但是如果你能够获取某个登录用户的session_id,用特殊的浏览器伪造该用户的请求也是能够成功的。

session_id是服务器和客户端链接时候随机分配的,一般来说是不会有重复,但如果有大量的并发请求,也不是没有重复的可能性。

Session是由应用服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的SessionID,用该SessionID 为标识符来存取服务器端的Session存储空间。而SessionID这一数据则是保存到客户端,用COOKIE保存的,用户提交页面时,会将这一 SessionID提交到服务器端,来存取Session数据。这一过程,是不用开发人员干预的。所以一旦客户端禁用COOKIE,那么Session也会失效。

2、COOKIE不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。

3、设置COOKIE时间可以使COOKIE过期。但是使用session-destory(),我们将会销毁会话。

4、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。

5、单个COOKIE保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个COOKIE。(Session对象没有对存储的数据量的限制,其中可以保存更为复杂的数据类型)

注意:

session很容易失效,用户体验很差;虽然COOKIE不安全,但是可以加密 ;COOKIE也分为永久和暂时存在的;浏览器 有禁止COOKIE功能 ,但一般用户都不会设置;一定要设置失效时间,要不然浏览器关闭就消失了;例如:记住密码功能就是使用永久COOKIE写在客户端电脑,下次登录时,自动将COOKIE信息附加发送给服务端。application是全局性信息,是所有用户共享的信息,如可以记录有多少用户现在登录过本网站,并把该信息展示个所有用户。

两者最大的区别在于生存周期,一个是IE启动到IE关闭.(浏览器页面一关 ,session就消失了),一个是预先设置的生存周期,或永久的保存于本地的文件。(COOKIE)

Session信息是存放在server端,但session id是存放在client COOKIE的,当然php的session存放方法是多样化的,这样就算禁用COOKIE一样可以跟踪

COOKIE是完全保持在客户端的如:IE firefox 当客户端禁止COOKIE时将不能再使用



4.介绍下flask

Flask是一个使用 Python 编写的轻量级 Web 应用框架。

Flask的socket是基于Werkzeug 实现的,模板语言依赖jinja2模板



5.介绍下gin

Gin 是一个 Go 写的 web 框架,具有高性能的优点。

Gin 是 Go语言写的一个 web 框架,它具有运行速度快,分组的路由器,良好的崩溃捕获和错误处理,非常好的支持中间件和 json。



6.Redis能存储的数据类型


  1. 字符串string
  2. 列表list
  3. 散列hash
  4. 集合set
  5. 有序集合sorted set

https://blog.csdn.net/weixin_33947521/article/details/93823167?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control



7.Redis常用命令

Redis 常用命令
登录 redis-cli -p 5566 -a password
检查key是否存在 EXISTS key
搜索某关键字 KSYS *4
返回一个Key所影响的vsl的类型 TYPE key

1 String
设置一个键的值 SET key value
获取一个建的值 GET key
删除键对 DEL key
同时获取多个 mget key1 key2

2 Hash
设置一个hash HMSET key valueKey value -->
获取hash所有key&value HGETALL key
获取hash所有key HKEYS key
获取hash所有key的vslue HVALS key
获取hash内键值对的长度 HLEN key
给一个hash的某个键值对赋值 HSET key valueKey value
当hash中valueKey不存在时赋值 HSETNX key valueKey value

3 List
给list赋值 LPUSH listName value
按照索引取值 LINDEX listName 1



8.c++模板编程

template <模板形参表>
函数返回类型 函数(形参表){函数体;
};

例如&#xff1a;

template <typename T>
inline const T& Max(const T& a, const T& b){return a>b?a:b;
}Max(2,10);



9.中序遍历递归&#xff0c;非递归

递归&#xff1a;

void dfs(TreeNode* root, vector<int> &data){if(!root)return;dfs(root->left,data);data.emplace_back(root->val);dfs(root->right,data);
}

非递归&#xff1a;

/*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode(int x) { val &#61; x; }* }*/
class Solution {public List<Integer> inorderTraversal(TreeNode head) {List<Integer> list&#61;new ArrayList<Integer>();Stack<TreeNode> stack&#61;new Stack<TreeNode>();if (head!&#61;null) {while(head!&#61;null||!stack.empty()) {if(head!&#61;null) {stack.push(head);head&#61;head.left;}else {head&#61;stack.pop();list.add(head.val);head&#61;head.right;}}}return list;}
}



10.两数之和

vector<int> twoSum(vector<int>& numbers, int target) {unordered_map<int,int> mp;for(int i&#61;0;i<numbers.size();i&#43;&#43;){if(mp.count(target-numbers[i])){return {mp[target-numbers[i]],i&#43;1};}else{mp[numbers[i]]&#61;i&#43;1;}}return {};}



11.实现strcat&#xff0c;strcpy

实现strcat&#xff1a;把src所指字符串添加到dest结尾处(覆盖dest结尾处的’\0’)

char* myStrcat(char* pre, const char* next)
{if (pre &#61;&#61; nullptr || next &#61;&#61; nullptr) // 如果有一个为空指针&#xff0c;直接返回prereturn pre;char* tmp_ptr &#61; pre &#43; strlen(pre); //strlen计算字符数&#xff0c;需要包含都文件string.h&#xff0c;当然也可以自己实现while ( (*tmp_ptr&#43;&#43; &#61; *next&#43;&#43;) !&#61; &#39;\0&#39;); // 依次接着赋值return pre;
}

实现strcpy&#xff1a;复制字符串

char* myStrcpy(char* pre, const char* next)
{if (pre &#61;&#61; nullptr || next &#61;&#61; nullptr) //空指针直接返回{return nullptr;}if (pre &#61;&#61; next) // 两者相等也无需拷贝了return pre;while ((*pre&#43;&#43; &#61; *next&#43;&#43;) !&#61; &#39;\0&#39;); // 依次赋值给主字符数组return pre;
}



12.手写非重复最长公共子序列

class Solution {
public:int lengthOfLongestSubstring(string s) {map<char, int> mp;int res&#61;0,max_res&#61;0;for(int i&#61;0;i<s.length();i&#43;&#43;){int last_pos&#61;mp.count(s[i])?mp[s[i]]:-1;mp[s[i]]&#61;i;if(res>&#61;i-last_pos)res&#61;i-last_pos;elseres&#43;&#61;1;max_res&#61;max(max_res,res);}return max_res;}
};



13.C&#43;&#43;什么时候只能用指针&#xff1f;什么时候只能用引用&#xff1f;

何时使用引用参数

  1. 程序员能够修改调用函数中的数据对象。
  2. 通过传递引用而不是整个数据对象&#xff0c;可以提高程序的运行速度。

在这里插入图片描述



14.const成员函数的作用&#xff1f;

程序通常不直接修改类对象。在必须修改类的对象时&#xff0c;应调用公有成员函数集来完成。为尊重类对象的常量性&#xff0c;编译器必须区分不安全与安全的成员函数(即区分试图修改类对象与不试图修改类对象的函数)

类的设计者通过把成员函数声明为const&#xff0c;以表明它们不修改类对象。例如&#xff1a;

class Screen {public:char get() const {return _screen[_cursor];}//...};

只有被声明为const的成员函数才能被一个const类对象调用。关键字const被放在成员函数的参数表和函数体之间。对于在类体之外定义的const成员函数&#xff0c;我们必须在它的定义和声明中同时指定关键字const。

注意&#xff0c;把一个修改类数据成员的函数声明为const是非法的。



15.为什么要提出右值引用&#xff1f;

右值引用允许从程序中其他地方无法引用的临时对象转移资源



16.对象指针如何找到对应的虚函数表&#xff1f;

类&#xff1a;有虚函数&#xff0c;这个类会产生一个虚函数表。
类对象&#xff1a;有一个指针&#xff0c;指针(vptr)会指向这个虚函数表的开始地址。类对象的虚函数表指针位置取决于编译器。


推荐阅读
author-avatar
穿越时空lily
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有