1. 介绍一下自己
2. 项目八股
登陆校验过程
使用auth2实现单点登陆,登陆过程如下:
- 用户访问客户端,客户端将用户请求转发到应用服务器
- 应用服务器将用户重定向到验证服务器,用户自行登陆验证
- 验证服务器给应用服务器返回授权码
- 应用服务器通过授权码和secret向验证服务器请求令牌
- 验证服务器给应用服务器返回令牌
Token的有效期:3600秒,刷新Token的有效期:7200秒
七层网络模型,每层的作用,为什么要分层
七层网络模型:应用层,表示层,会话层,传输层,网络层,数据链路层,物理层
- 应用层:为应用程序提供服务,例如HTTP,FTP,SMTP,DNS等
- 表示层:数据的表示、安全、压缩,例如ASCII码,加密等
- 会话层:建立、管理、终止会话,例如建立会话,终止会话等
- 传输层:定义传输数据的协议端口号,以及流控和差错校验,例如TCP,UDP等
- 网络层:进行逻辑地址寻址,实现不同网络之间的路径选择,例如IP协议,ICMP协议等
- 数据链路层:建立逻辑连接,进行硬件地址寻址,差错校验等功能
- 物理层:建立、维护、断开物理连接,确定传输的电平,速率等
分层的好处有以下几点:
模块化设计:分层将复杂的网络通信过程分解为更小的模块,使得网络设计、开发和维护更加简化和可靠。每个层次的功能明确,可以独立地进行开发和测试。
可扩展性:通过分层,可以在需要时添加新的功能层次,而不会对已有的层次造成太大的影响。这样可以更好地适应不断变化的网络需求和技术发展。
互操作性:不同厂商和组织可以根据相同的网络模型进行开发,保证了不同系统之间的互操作性。每个层次的功能和接口都是标准化的,可以确保不同系统之间的兼容性。
故障隔离:分层可以将网络问题限定在特定的层次,使得故障的定位和修复更加容易。当出现问题时,可以快速确定是哪个层次出现了故障,从而减少了故障排查的时间和成本。
总之,分层的网络模型提供了一种结构化和标准化的方法来设计和实现计算机网络,使得网络通信更加可靠、灵活和可扩展。
HTTP和HTTPS的区别
- HTTP是明文传输,HTTPS是加密传输,HTTPS使用SSL或TLS协议对数据进行加密,从而保证数据的安全性。
- 端口号不同,HTTP默认端口号为80,HTTPS默认端口号为443。
- HTTPS需要CA证书,HTTP不需要。
HTTPS使用的加密方式
HTTPS使用对称加密和非对称加密相结合的方式来保证数据的安全性。具体过程如下:
- 客户端向服务器发起HTTPS请求,连接到服务器的443端口。
- 服务器将自己的公钥证书发送给客户端。
- 客户端验证证书的合法性,如果证书合法,就生成一个随机的对称密钥,并使用服务器的公钥对其进行加密,然后将加密后的密钥发送给服务器。
- 服务器使用自己的私钥对客户端发送过来的密钥进行解密,得到对称密钥。
- 客户端和服务器使用对称密钥进行通信,从而保证数据的安全性。
哈希表冲突的解决方案
哈希表冲突的解决方案有以下几种:
- 开放定址法:当发生冲突时,使用某种探测技术在散列表中形成一个探测序列,直到找到一个空的散列地址,将其插入其中。探测技术包括线性探测、二次探测、双重散列等。
- 再哈希法:当发生冲突时,使用另一个哈希函数计算出一个新的散列地址,直到找到一个空的散列地址,将其插入其中。
- 链地址法:将散列到同一个地址的所有元素都放在一个链表中,这样,不会发生冲突。
- 建立公共溢出区:将散列到同一个地址的所有元素都放在一个公共溢出区中,这样,不会发生冲突。
红黑树的特点
红黑树是一种自平衡的二叉查找树,具有以下特点:
- 每个节点要么是红色,要么是黑色。
- 根节点是黑色。
- 每个叶子节点(NIL节点,空节点)是黑色的。
- 如果一个节点是红色的,则它的两个子节点都是黑色的。
- 对于每个节点,从该节点到其所有后代叶子节点的简单路径上,均包含相同数目的黑色节点。
字符串转化为数字需要考虑哪些问题
字符串转化为数字需要考虑以下几个问题:
- 字符串是否为空,是否为null。
- 字符串是否包含空格。
- 字符串是否包含正负号。
- 字符串是否包含非数字字符。
- 字符串是否超出了整数的范围。
public int myAtoi(String s) {
if (s == null || s.length() == 0) {
return 0;
}
int i = 0;
int sign = 1;
int res = 0;
while (i < s.length() && s.charAt(i) == ' ') {
i++;
}
if (i < s.length() && (s.charAt(i) == '+' || s.charAt(i) == '-')) {
sign = s.charAt(i) == '+' ? 1 : -1;
i++;
}
while (i < s.length() && s.charAt(i) >= '0' && s.charAt(i) <= '9') {
if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && s.charAt(i) - '0' > Integer.MAX_VALUE % 10)) {
return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
}
res = res * 10 + s.charAt(i) - '0';
i++;
}
return res * sign;
}
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin>>s;
int i = 0;
int sign = 1;
int res = 0;
while (i < s.length() && s[i] == ' ') {
i++;
}
if (i < s.length() && (s[i] == '+' || s[i] == '-')) {
sign = s[i] == '+' ? 1 : -1;
i++;
}
while (i < s.length() && s[i] >= '0' && s[i] <= '9') {
if (res > INT_MAX / 10 || (res == INT_MAX / 10 && s[i] - '0' > INT_MAX % 10)) {
return sign == 1 ? INT_MAX : INT_MIN;
}
res = res * 10 + s[i] - '0';
i++;
}
return res * sign;
}
SQL题目:如何查询一个表中的最后一条记录
select * from table_name order by id desc limit 1;
第二种:
select * from table_name where id = (select max(id) from table_name);
上述两种方法哪个更好,为什么?
从效率的角度来看,第二个查询语句的效率可能会更高。原因如下:
第一个查询语句使用了ORDER BY对整个表进行排序,然后再通过LIMIT只返回最大值的一条记录。在数据量较大的情况下,排序操作可能会消耗较多的时间和资源。
第二个查询语句使用了子查询,先通过子查询获取到最大值,然后再通过WHERE条件筛选出对应的记录。这种方式避免了对整个表进行排序的操作,可能会更加高效。
将一个数组中的非0元素前移,比如[1,3,0,9,0,4]->[1,3,9,4,0,0]
#include<bits/stdc++.h>
using namespace std;
int main(){
vector<int> nums = {1,3,0,9,0,4};
int j = 0;
for(int i = 0; i < nums.size(); i++){
if(nums[i] != 0){
nums[j++] = nums[i];
}
}
for(int i = j; i < nums.size(); i++){
nums[i] = 0;
}
for(int i = 0; i < nums.size(); i++){
cout<<nums[i]<<" ";
}
return 0;
}