面经总结-仅供参考

别等时光非礼了梦想. 提交于 2019-12-20 21:04:52

面经总结-仅供参考

1 服务器如何判断客户端连接不上了

1 recv()返回值小于等于0,如果errno == EINTR 则说明recv函数是由于程序接收到信号后返回的,socket连接还是正常的,不应close掉socket连接。
2) 服务器一段时间内没接收到客户端心跳包反馈
3)
struct tcp_info info;
int len=sizeof(info);
getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
if((info.tcpi_state==TCP_ESTABLISHED)) 则说明未断开 else 断开

int keepAlive = 1; // 开启keepalive属性
int keepIdle = 60; // 如该连接在60秒内没有任何数据往来,则进行探测
int keepInterval = 5; // 探测时发包的时间间隔为5 秒
int keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void )&keepAlive, sizeof(keepAlive));
setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void
)&keepIdle, sizeof(keepIdle));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

设置后,若断开,则在使用该socket读写时立即失败,并返回ETIMEDOUT错误

2 心跳包多长时间发一次,如何判断客户端下线了

–(局域网内)3秒发一次,服务器10秒没收到客户端心跳包认为下线

3 四次挥手 通过什么接口来判断?????

– struct tcp_info info;
int len=sizeof(info);
getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
if((info.tcpi_state==TCP_ESTABLISHED)) 则说明未断开 else 断开

4 epoll只能练500-1000个连接,有没有判断是什么原因引起的

1)linux系统会限制文件打开个数(ulimit -a查看),
–临时修改
ulimit -HSn 2048
–永久修改
vi /etc/security/limits.conf
2)服务器硬件限制

5 noSQL-redis

6 消息队列-应用场景

7 微服务容器

它不仅打包了本地应用程序,而且还将本地环境(操作系统的一部分)也打包了,组成一个叫做「 Docker镜像 」的文件包。所以这个「 Docker镜像 」就包含了应用运行所需的全部依赖,我们可以直接基于这个「 Docker镜像 」在本地进行开发与测试,完成之后,再直接将这个「 Docker镜像 」一键上传到云端运行即可。
Docker容器里虽然带有一部分操作系统(文件系统相关),但它并没有内核,因此多个容器之间是共用宿主机的操作系统内核的。
Namespace 技术 只能改变一下进程组的视觉范围
Cgroup技术提供的功能就是实现对内存、磁盘等这些资源进行限制

8 虚函数析构函数和普通虚函数区别,及原因,析构顺序

析构函数不一定必须是虚函数,是否为虚函数取决于该类的使用,一般该类为基类产生继承和多态时,才会是虚函数,单独使用可以不是虚函数。之所以在继承和多态时设计为虚函数是因为当new派生类并且用基类指针指向这个派生类,在销毁基类指针时只会调用基类的析构函数,不会调用派生类的析构函数,因为基类无法操作派生类中非继承的成员,这样就造成派生类只new无法delete造成内存泄露。 2.默认不是虚析构函数是因为如果析构函数为虚函数就需要编译器在类中增加虚函数表来实现虚函数机制,这样所需内存空间就更大了,因此没有必要默认为虚析构函数。

class B
{
}
class C : public B
{
}
class D : public B
{
}
D* pD = new D();//pD的静态类型是它声明的类型D*,动态类型也是D*
B* pB = pD;//pB的静态类型是它声明的类型B*,动态类型是pB所指向的对象pD的类型D*
C* pC = new C();
pB = pC;//pB的动态类型是可以更改的,现在它的动态类型是C*

构造:先基类,后派生类
析构:先派生类,后基类

class B
  {
   virtual void vfun(int i = 10)
   {
       cout << "B:vfun, i = " << i;
       cout << endl;
   };
      public:
   void modfuc()
   {
       vfun();
   }
   virtual~B()
   {
       cout << "B:~vfun" << endl;
   }
  };
  
  class D : public B
  {
   virtual void vfun(int i = 20)
   {
       cout << "D:vfun, i = " << i;
       cout << endl;
   };
  
   void modfuc()
   {
       vfun();
   }
      public:
   ~D()
   {
       cout << "D:~vfun" << endl;
   }
  };
  
  int main()
  {
      D* pD = new D();
      B* pB = pD;
  
      pB->modfuc();//调用子类vfunc,但是入参是默认参数,静态绑定的所以输出为10,调用基类的i=10
      delete pD;
  }

在这里插入图片描述
9 边沿触发和水平触发区别,边沿触发会引发什么问题
Level Triggered (LT) 水平触发
.socket接收缓冲区不为空 有数据可读 读事件一直触发
.socket发送缓冲区不满 可以继续写入数据 写事件一直触发
符合思维习惯,epoll_wait返回的事件就是socket的状态

Edge Triggered (ET) 边沿触发
.socket的接收缓冲区状态变化时触发读事件,即空的接收缓冲区刚接收到数据时触发读事件
.socket的发送缓冲区状态变化时触发写事件,即满的缓冲区刚空出空间时触发读事件
仅在状态变化时触发事件
LT的编程与poll/select接近,符合一直以来的习惯,不易出错
ET的编程可以做到更加简洁,某些场景下更加高效,但另一方面容易遗漏事件(只提醒一次,需循环接收accept()),容易产生bug

10 Redis为什么是单线程的

原因一:redis本身就是基于内存操作的,所以每个操作执行速度都很快。

如果使用多线程,就需要解决多线程同步的问题,就会涉及到线程的频繁切换而消耗CPU。单线程的使用避免了不必要的上下文切换和竞争条件,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。

原因二:redis中的数据结构比较简单,对数据的操作也就比较快。

原因三:使用多路复用IO,即非阻塞IO。这样提高了redis的吞吐量。多路是指可以处理多个网络连接产生的流,复用是指一个线程可以服务多条IO流
缺点就是在多处理器情况下,不能充分利用其他CPU。可以的解决方法是开启多个redis服务实例,通过复制和修改配置文件,可以在多个端口上开启多个redis服务实例,这样就可以利用其他CPU来处理连接流。

11 不同机器进程间如何通信:

socket

12 服务器如何转发消息的

ret = recv(*(int *)arg, &RecvBuf, sizeof(RecvBuf), 0);
ret = send(RecvBuf.ToFd, &RecvBuf, sizeof(RecvBuf), 0);
接收客户端A的消息包,从包中取出A需要发送到B的地址,然后服务器把A的消息转发给B
服务器如何转发离线消息(消息队列)

14 西安发消息到上海,接收方消息延迟了,原因

网络原因+客户端内存

15客户端发了很多消息,服务器怎么及时处理?

搭建服务器集群按业务划分去处理,各个业务服务器之前可以加负载均衡,使用户均匀的分布在各个服务器上。
优点:当某一个服务器故障,不会影响所有用户,只会影响到连接到这个服务器的用户。

16客户端收到大量数据会导致客户端卡顿,怎么优化?

客户端数据可以分页显示处理,比如一共有1000页数据,客户端一页可以显示10条,那就按照每次10条显示在客户端,当用户想查询下一页时再拉取下一页的数据显示,直到数据末尾。

17. 十几个日志文件,用什么shell命令可以筛选出自己想要的日志内容

grep -r key 路径

18. 客户端连接不上服务器的问题一般怎么定位?(未解决)

ping、检查IP/PORT、netstat xxx查询连接状态

19. 多进程文件怎么共享,为什么要用mmap。

常规文件操作需要从磁盘到页缓存再到用户主存的两次数据拷贝。而mmap操控文件,只需要从磁盘到用户主存的一次数据拷贝过程。说白了,mmap的关键点是实现了用户空间和内核空间的数据直接交互而省去了空间不同数据不通的繁琐过程。因此mmap效率更高。

mmap优点总结
由上文讨论可知,mmap优点共有一下几点:

1、对文件的读取操作跨过了页缓存,减少了数据的拷贝次数,用内存读写取代I/O读写,提高了文件读取效率。

2、实现了用户空间和内核空间的高效交互方式。两空间的各自修改操作可以直接反映在映射的区域内,从而被对方空间及时捕捉。

3、提供进程间共享内存及相互通信的方式。不管是父子进程还是无亲缘关系的进程,都可以将自身用户空间映射到同一个文件或匿名映射到同一片区域。从而通过各自对映射区域的改动,达到进程间通信和进程间共享的目的。

20. vi打开文件后,怎么替换无数个想要替换的内容

:%s/vivian/sky/g(等同于 :g/vivian/s//sky/g) 替换每一行中所有 vivian 为 sky

21. 10W个用户怎么连接服务器

–每个连接一个fd,linux加大文件打开数限制,加心跳包
–单服务器只有多线程配合强大硬件。最好用多服务器,使用队列协同。
–服务器ip、服务器端口、客户端ip、客户端端口4个因素形成一条唯一连接。记得服务器的ip和端口总是不变的,就是监听的那个。所以不存在端口不够用的问题
–负载均衡和服务器的集群

NIO模型:
在这里插入图片描述
来源连接

分离:登录服务器、通讯服务器、消息服务器 和 数据库服务器;
◎登录服务器(有状态):除给Client提供登录和分配通讯服务器外,重点功能是提供关于用户目前连接在哪台服务器上的查询,所以所有查询基本基于缓存完成;考虑到单点故障问题,登录服务器应双机冗余,但不能太多,否则双机之间的缓存同步代价太高;缓存可使用开源组件。
◎通讯服务器(有状态):负责维护消息长连接,以及消息的收发;通讯服务器缓存自身的所有用户连接信息,和部分(这个要时情况动态调整)非自身的热点用户连接信息(即该用户连在哪台通讯服务器上);消息到达时,将消息转发给消息服务器进行落地;然后根据目标最终用户先查询本地表,查不到就去查询登录服务器;然后直接寻找目标通讯服务器,发送消息到达的通知;通讯服务器的问题是没有Failover,但是也不重要,客户端连接不上就由登录服务器重新分配新的通讯服务器来提供服务即可。
◎ 消息服务器(无状态):负责接收通讯服务器所发来的消息,批量写入数据库中,以及供其它消息服务器存取;另外也提供历史消息查询这类辅助性功能;因为是无状态,所以集群较为简单,略。
◎ 数据库服务器:略。

22. select可以连接2000个客户端吗?

select上限1024个

23. libevent怎么用的?

24. 链表顺序不变,如何排序

数组存指针有序的指向链表节点,输出

25. 硬盘大小不变,服务器只能连接1000个,要连10万个怎么办?

linux加大文件打开数限制
负载均衡和服务器的集群

26 tcp客户端能连接的最大长连接,与几个因素有关,可以超越65536

(1) 进程能打开的最大描述符
(2) IP_TABLE的限制
(3) 临时端口范围
(4) 内存大小

二、调整能打开的最大文件描述符

$ echo “655350” > /proc/sys/fs/file-max
$ vi /etc/security/limits.conf

* soft nofile 655350  
* hard nofile 655350

三、调整临时端口范围与IP_TABLE限制(centos7)
$ vim /etc/sysctl.conf

#临时端口范围
net.ipv4.ip_local_port_range = 10000 65535

#Linux网络内核的IP_TABLE防火墙对最大跟踪的TCP连接数有限制
net.netfilter.nf_conntrack_max = 655350
net.nf_conntrack_max = 655350

27 ping一个域名的过程

28 客户端架构设计

四层架构
在三层架构的基础上多了业务规则层,通常的三层是把业务逻辑和业务规则合并为一个层,统称为业务层.业务规则层的提出,既可以及时处理用户输入的不合法信息, 又可以及时处理数据库错误, 增大了业务逻辑层的结构清晰度, 让业务逻辑人员专心致志做逻辑。

从上至下为:
l 表示层
l 业务规则层
l 业务逻辑层或称为领域层
l 数据访问层

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!