三七互娱是国内的一家游戏公司,我投了他们今年的春招,并且在前天完成了一面,可惜,没过。下面我来讲下前天的面试题。

讲讲TCP的四次挥手

自我介绍后这个是第一个面试题,当时这个题目我回答是回答出来了,但可能言语逻辑没有理清楚,所以效果应该不咋的。下面给出答案:
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送(报文段4)。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
(3)服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)

为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的建连请求后,它可以把ACK和SYN(ACK起应答作用,SYSN起同步作用)放在同一个报文来发送。但是关闭连接后,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。

讲一讲TCP和UDP的区别

这个问题也不难,主要考察对TCP和UDP的基本了解。
1:TCP的面向连接的(传输数据前要建立连接),UDP是无连接的。
2:TCP是面向字符流的,UDP是面向报文的。
3:TCP是一种可靠的传输(无差错,不丢失,不重复,且按序到达),UDP不可靠,尽最大努力交付。
4:TCP是点对点的,UDP可以一对一,一对多,多对多。
5:UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性比较高的通讯或广播通信。随着网速的提高,UDP使用越来越多。
6:TCP对系统资源要求比较高,UDP对资源要求较少。
7:TCP的首部字节是20字节,UDP的则是8个字节。

TCP怎么实现可靠传输,如何实现UDP的可靠传输

这个问题当时我没有回答出来,以前看计网的时候记得看到过这个解决方法,当时前天忘记了。
TCP实现可靠传输主要是有三种机制:重传机制、确认机制、以及滑动窗口(这个当时也问了,并要求说出工作原理)。
UDP要实现可靠传输,在运输层上是不行了,只能通过应用层来实现了。实现的方式可以参照tcp可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。实现确认机制,重传机制,以及窗口确认机制。目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。这里就不一一介绍了,又想了解详情的可以去这个博客看看,这段也是借鉴了这篇博客的。
()

说一说时间复杂度为O(log n)的数据结构

这个我当时答错了,后面去网上找了下发现是
Tree-based dictionary (SortedDictionary<K,T>)和Tree based set(SortedSet),额,这个到现在我不是很懂。我说了数组和链表,然后就问了我数组合链表的区别,这个很简单,十个程序员十一个都答得出来,数组查找快,增删慢,链表则是查找慢,增删快。然后深入问了下数组为什么增删慢呢。这个我没答到点上。正确结果应该是:数组属于顺序结构,用一段连续的内存位置来 存储。链表属于链接存储,用一组任意的存储单元来存储,不要求相邻。CPU缓存会读入一段连续的内存,顺序存储符合连续的内存,所以顺序存储可以被缓存处理,而链接存储并不是连续的,分散在堆中,所以只能内存去处理。所以数组查询比链表要快。而数组大小固定,插入和删除都需要移动元素,链表可以动态扩充,插入删除不需要移动元素,只需要更改元素中的指针。所以链表的插入删除比数组效率高。想知道详情的可以去看看这个博客:(https://www.jianshu.com/p/35666023469c)

说一说Spring的循环依赖,并如何解决,解释解释源码

Spring的循环依赖有两种,一种是指构造器依赖和属性循环依赖,其中构造器循环依赖无法解决,因为在构造器注入时,本身的实例无法生成;如果强行使用,将导致不安全的发布,从而导致各种未知的问题!只能抛出BeanCurrentylyInCreationException异常表示循环依赖。另一种依赖属性循环依赖的解决办法是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的bean来完成的。通过提前暴露一个单例工厂方法,从而使其他bean能够引用到该bean。也就是我们说的自动注入要用setter()注入。至于源码当时没有回答出来,因为也没去看过。下面这个文章介绍的很详细,感兴趣的可以去看看:()

索引的存储结构以及实现原理

当建立了索引后,它一般以文件的形式保存在磁盘是,存储结构是以B+ tree的格式保存的。
在B+Tree中key检索数据算法如同目录:首先从根节点进行二分查找,从左(小)边到右(大)匹配,找到key匹配成功的索引值,根据索引值对应的节点地址,进入节点地址key继续进行匹配,直到进入叶节点,再根据key获取数据。在B+Tree的每个叶子节点增加一个指向相邻叶子节点的指针,就形成了带有顺序访问指针的B+Tree。做这个优化的目的是为了提高区间访问的性能。
注意:每个索引的最小值,也就是子索引的最小值,依次类推,最后的子索引的最小值,也就是该数据页的key索引的最小值。最小值都是靠最左边排列。都是节点开始的第一个值。
注意:叶节点的数据页存有邻近的数据页节点地址,可以通过数据页的节点直接进入邻近数据页,查询需要的主键索引值。

好吧,到这里基本上就结束了,后面问了一下Redis的基本问题和Spring的源码,有些答出来了,有些没有,涉及到源码这一块我真的不是很熟练。然后问了些和项目相关的问题。

总结

这些问题还是很有针对性的,难得也有,简单的也有,面试官人也很好,有时候会提醒我一些。可能有一两个问题我忘记了,但大致就是以上那些,这些问题还是很有针对性的,第一面就挂了,还是很伤心的,总之继续努力的。