非技术题目
-
根据脚本或成熟项目搭建游戏服务器(MC,泰拉,饥荒),在服务器上部署已成熟项目(如Astrbot,BiliBiliToolPro,Alist(虽说现在已经被收购力,后续打算换成openlist)),
给QQ还有游戏什么的装插件算吗?,之前用ai写过前后端做了个小网页给朋友过生日 -
学习了go的基本语法,包括基本类型,函数,还有接口,泛型,迭代器,文件,反射,并发,以及标准库中的net/http包1,以及简单的echo框架 2
(虽然边学边忘就是了),还有非常简单的数据库(只是了解,然后在wsl中部署了PostgreSQL),了解了Cookie-Session,OAuth,了解了对称加密和非对称加密,学习了Nginx的设计思路,包括反向代理,负载均衡,多进程,异步非阻塞,Master-Worker,缓存机制,复习了git的用法。 -
互联网的话,我觉得感觉已经发展的很成熟了,做很多事情都有成熟的框架,但我觉得里面还有很多可能,尤其是对我来说。对于产品,不敢说很好的想法,
但是感觉现在食堂的信息有点散,评价分布在各个平台,能不能做一个专门发表食堂美食评价的app,有评价,评分,位置,菜品,价格等功能。(发现有了Huster吃什么这个小程序,但是知名度不是很高,而且现在位置权限也获取不了) -
保研是想的
(听说保研不用考政治?我是真的不喜欢),但主要是想提升自己吧(各方面的),目标就是有什么软件的想法都可以立刻付诸实践,随时都能做喜欢的产品,目前我还是一个比较理想的人,对就业什么考虑不多,感觉钱什么的只要能满足自己爱好就行了。谈恋爱不考虑。 -
没有(本来想报联创的,当天他们系统出bug,后来感觉我比较喜欢做产品,也就没报了)
计算机基础
- 前序:冰岩后端组很酷不是吗
中序:组端很后酷岩冰是不吗
解决程序
class TreeNode: '''问了ai,查了教程后看懂了,这应该是递归遍历''' def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right
def preorder_traversal(root): """前序遍历""" if not root: return [] return [root.val] + preorder_traversal(root.left) + preorder_traversal(root.right)
def inorder_traversal(root): """中序遍历""" if not root: return [] return inorder_traversal(root.left) + [root.val] + inorder_traversal(root.right)
def postorder_traversal(root): """后序遍历""" if not root: return [] return postorder_traversal(root.left) + postorder_traversal(root.right) + [root.val]
# 构建树 root = TreeNode('冰') root.left = TreeNode('岩') root.right = TreeNode('不') root.left.left = TreeNode('后') root.right.left = TreeNode('是') root.left.left.left = TreeNode('端') root.left.left.right = TreeNode('酷') root.right.left.right = TreeNode('吗') root.left.left.left.left = TreeNode('组') root.left.left.left.right = TreeNode('很')
# 输出结果 print("前序遍历:", preorder_traversal(root)) print("中序遍历:", inorder_traversal(root)) print("后序遍历:", postorder_traversal(root))- 将filename设置为../app.py。使用—reload的话,flask就会监测app.py的变化,我猜filename为../app.py的话会被覆盖然后执行,在里面可以写入恶意代码(具体我不知道)
防护措施的话有:1.限制检测文件名(如后缀不能是py等)2.限制检测文件路径 3.不使用—reload参数(但是文件还是可能被覆盖?)
-
让ai解释了一下这段代码的意思,很明显可能会有溢出的问题(你要用python写我不就懂了吗),构造a=INT_MIN,b=0,c=1,这样a<b,b<c,但a>c(a-c会由于整数下溢而=INT_MAX) 直接改为使用<>比较应该就行了
int cmp(const void * const pa, const void * const pb){const int a = *(const int *)pa;const int b = *(const int *)pb;if (a < b) return -1;if (a > b) return 1;return 0;} -
常用方法:get,post,put,delete get:获取 post:创建新资源 put:更新资源 delete:删除资源 1XX类状态码信息表示:临时的响应。客户端在收到常规响应之前,应准备接收一个或多个1XX响应 2XX类状态码信息表示:服务器成功的接收了客户端请求 3XX类状态码信息表示:客户端浏览器必须采取更多操作来实现请求。例如,浏览器可能不得不请求服务器上的不同页面,或者通过代理服务器重复该请求 4XX类状态码信息表示:发生错误,客户端似乎有问题。例如:客户端请求不存在的页面,客户端为提供有效的身份验证信息 5XX类状态码信息表示:服务器遇到错误而不能完成该请求5
-
用户使用的时候不小心访问了删除api(感觉可能性比较低),有爬虫(这算他人攻击吗)?(后来问了AI,可能是搜索引擎(也是爬虫)访问了删除api)
-
a. ①DDoS6:里面好像分很多,我只知道发送大量udp数据包来耗尽目标服务器的资源(但是好像伤敌一千,自损八百)
②SQL注入7:攻击者在输入中恶意注入SQL语句,使得当输入与后端SQL查询代码拼接在一起时会执行恶意的查询并返回结果而导致重要数据泄漏
b. ①使用cdn8或限制每秒的请求次数 ②校验用户发来的数据
- a.限制每秒访问次数
b.校验发送短信的对象,禁止短时间内向同一用户发送大量短信,就像短信验证码的60秒倒计时9
这题我会
1.使用虚拟机(如VirtualBox)原理:使用虚拟化模拟出一个完整的计算机。安全性:挺高的,基本完全隔离 (总不会遇到虚拟机逃逸吧?) 。性能:一般(虚拟化要模拟完整硬件,有些不是必须的,因此性能有损耗)。操作复杂度:感觉挺简单的
2.使用docker容器技术 原理:将docker进程和其他进程隔离,使用Docker运行Alpine Linux容器。安全性:也比较高,但应该比虚拟机低。性能:不错,没有冗余重复文件,系统开启耗时和系统行为重复的问题。操作复杂度:有点吧,要下docker,要配置镜像源,要pull然后run
3.安装双系统 原理:在硬件层面装两个系统。安全性:很强,毕竟都是不同系统了。性能:很高,毕竟直接调用硬件。操作复杂度:很高,要配置引导什么的,本来想过装双系统,但被我的一个装过双系统的朋友劝退了,据说系统容易炸而且文件不好管理
Golang
-
A,D
-
B
-
原版map可能存在多个协程同时对一对键值对进行写入,这样就会引发并发错误,而且哪怕一个协程在读一对键值对,一个协程在写另一对键值对也会引发fatal,这是因为读的时候会检查
hashWriting标志, 如果有这个标志,就会报并发错误,写的时候会设置这个标志:hashmap.go#L542。然后sync.map解决的方式就是创建两个map,一个read,一个dirty,其中read是原子类型,只用来读,因此不会有并发安全问题,read是dirty的子集,dirty可读可写,当对dirty进行操作时要加锁。当读取时先从read读,若是read中没有则从dirty中读(amended = true)。当写入时,先尝试更新read map中已存在的entry,如果read中不存在,加锁操作dirty map,而当misses达到阈值时,将dirty提升为read,这样就解决了数据竞争的问题。1011 -
a:
true;b:false;c:false
原因:用var声明变量时会存储一个零值,而切片的零值时nil,而用[]int{}则构造了一个空的切片但不为nil,make函数返回的同样是个空切片(规定长度是0)但不为nil1
-
修改:使用WaitGroup等待协程完成利用管道发送信号使两个协程相继进行(由ai提供思路)
package mainimport ("fmt""math/rand""sync""time")var someNumber intfunc main() {someNumber = 0totalIterations := 0var wg sync.WaitGroupwg.Add(1)signal1 := make(chan struct{})signal2 := make(chan struct{})go func() {//当signal为空时阻塞for range signal1 {someNumber -= 1time.Sleep(3 * time.Millisecond)// 发送信号使+2协程继续signal2 <- struct{}{}}}()go func() {defer wg.Done()for {someNumber += 2// 发送信号使-1协程继续signal1 <- struct{}{}// 当signal2为空时阻塞,直到-1协程完成+1操作并发送信号<-signal2totalIterations += 1time.Sleep(time.Duration(rand.Intn(5)) * time.Millisecond)fmt.Println("someNumber:", someNumber)if someNumber >= 100 {fmt.Println("Total iterations:", totalIterations)close(signal1)break}}}()} -
问题:两个进程同时操作
map只要至少一个是写操作就会引发fatal(AI发现) 修改:使用读写锁控制(修改了三次,每次都问AI修改的是否正确)package mainimport ("net/http""sync""github.com/gin-gonic/gin")var rw sync.RWMutexfunc main() {r := gin.Default()m := make(map[string]int)r.Use(func(c *gin.Context) {name := c.Query("name")if name == "" || name == "hacker" {c.JSON(http.StatusUnauthorized, gin.H{"message": "Invalid User",})c.Abort()return}c.Next()})r.GET("/hello", func(c *gin.Context) {name := c.Query("name")rw.Lock()m[name]++rw.Unlock()c.JSON(http.StatusOK, gin.H{"message": "hello " + name,})})r.GET("/users", func(c *gin.Context) {rw.RLock()mcopy := make(map[string]int, len(m))for k, v := range m {mcopy[k] = v}rw.RUnlock()c.JSON(http.StatusOK, gin.H{"users": mcopy,})})r.Run()}
其他语言
-
①众所周知,c++是c的超集,c是面向过程编程,c++可以面向对象编程,也支持函数式编程(编程范式)
②我不这么认为
(虽然我既不会c也不会c++),stl只是多了很多好用的功能,但我感觉c到c++这种由面向过程到面向对象的编程思想的转变才是更为关键与重要的。 -
B(AI做的,同时问了四个,c,c++,rust我完全不会,以后会学,但现在没时间)
-
[](){}(); - 定义并立即调用lambda表达式,空函数体,什么都不做但语法完美。[]{{}}; - lambda表达式,函数体内是空的复合语句{{}},优雅的嵌套。({{{}}}); - 三层大括号嵌套在括号表达式中,纯粹的语法艺术。{}[](){}; - 空初始化列表、数组下标运算符、函数调用、空语句的奇妙组合。(AI写的,我只知道lambda表达式应该是匿名函数,在go里面可以来实现闭包,python中我是不怎么用) -
问了ai,他说原理是:运算符重载,就是用函数的形式定义“当运算符遇到我这个类时该怎么办”,这样就能让自定义类的操作像内置类型一样自然。(不会c++,但运算符重载倒是听说过,好像java不支持,python支持)
-
不会
-
使用更快的链接器 启用并行编译 使用增量编译 调整优化级别 依赖预编译优化2
-
不会
-
GIL全称是Global Interpreter Lock,全局解释器锁,其实感觉和go并发中经常用到的互斥锁是一样的作用,它会限制同一时刻只有一个线程在执行 Python 字节码,因为cpthon的内存管理在多线程的时候是内存不安全的,这个锁是为了防止内存错误或崩溃的。
-
111
操作系统/计网/数据库等
-
不会c语言呢
-
终于有会的了client(客户端)在这里应当指的就是用户的浏览器,属于发出请求的一方 server(服务端)在这里指的就是百度的服务器(拥有公网ip和域名),是给出响应的一方 整个过程是这样的:首先浏览器通过DNS服务器将 www.baidu.com 这个域名解析为一个ip,然后浏览器和服务器通过TCP/IP协议与服务器建立联系(这个过程有三次握手,具体查了下),这里是https连接,所以应该还有SSL/TLS 握手,之后浏览器向服务器发送https请求(加密,这里应该是GET请求),之后服务器处理请求后返回响应,然后浏览器解析响应关闭连接。 -
tcp需要建立连接,udp不需要,tcp较为可靠安全,udp则不保证,tcp资源消耗多,udp消耗少 tcp:访问网页 udp:即时通讯(如果我没记错的话,qq用的就是udp协议)
-
不会捏
-
不会喵
-
在学
-
111
工具和命令
-
经典,我服务器也是 首先,输入ll或ls -l,命令行会输出文件总数和该目录下各个文件及其权限,链接数,属主名,属组名,文件大小,时间,文件名,主要看权限(最前面是d说明这是个目录),权限字母三个一组,从左往右依次代表属主权限,属组权限,其他用户权限。大概率你会发现你没有执行权限(X)这是输入chmod u+x ./bingyan并回车,这个命令中chmod意思是change mode,u(user)指对属主权限进行操作,+x指增加x(执行)权限,./bingyan就是要修改权限的默认文件名,因此这个指令的意思就是向bingyan这个文件的属主添加执行权限。这样应该就能执行了。
-
2
-
首先,nginx是一个多进程的架构(因为多线程的上下文切换开销过大),它有一个master进程和多个worker进程(含有多个模块,通常worker进程数是cpu核心数)。master进程负责管理worker进程,包括配置重载、worker进程的启动和停止,不处理实际请求;每个worker进程都在监听同样设置的socket fd,这意味着当有一个请求进来的时候,所有的worker都会感知到,产生所谓的“惊群现象”,为了使只有一个进程注册到listenfd的读事件(?)nginx实现了“accept_mutex”(类似互斥锁,只有获得这个锁的进程才可以去注册读事件),最后,监听成功的worker进程,读取请求,解析处理,响应数据返回给客户端,断开连接。同时,Nginx采用了一个是否打开accept_mutex选项的值(nginx单进程的所有连接总数的八分之一,减去剩下的空闲连接数量) 当ngx_accept_disabled大于0时,不会去尝试获取accept_mutex锁,并且将ngx_accept_disabled减1,当空闲连接多时,worker正常枪锁,当这个worker的连接数增长时。ngx_accept_disabled变为正数,让出获取链接的机会,时其他worker能获取连接,实现负载均衡。此外,nginx采用了事件驱动的异步非阻塞模式,使用epoll(当某个连接有数据操作时才通知应用程序,epoll使用队列存储有时间的连接,这就是事件驱动的方式)等IO多路复用技术监听大量socket连接,当有事件发生时才进行处理,避免了传统的一请求一线程模式下的资源浪费和上下文切换开销。(半抄半写的喵)12
-
不会喵
-
不会喵
-
不会喵
趣题
- 躲到缝隙里(有吗?),找一个刀片到不了的地方,跳出来(Google面试题答案)
- 不会啊
- ()
Footnotes
部分信息可能已经过时
鄂公网安备42011102005849号