[关闭]
@yiranblade 2016-10-21T07:38:45.000000Z 字数 5147 阅读 296

CreatShare2016服务端纳新笔试题参考答案

未分类


  1. 列出常见的关系型数据库和非关系型数据库。
    关系型:oracle sqlServer Sybase DB2 Access mysql 非关系Redis Flare MongoDB等
    ps:列出并说明了每种数据库的适用范围的话加分
  2. 谈谈你对数据库和数据仓库的理解。
    数据仓库:数据仓库(Data Warehouse)是一个面向主题的(Subject Oriented)、集成的(Integrate)、相对稳定的(Non-Volatile)、反映历史变化(Time Variant)的数据集合,用于支持管理决策。
    数据库:数据库(Database)是按照数据结构来组织、存储和管理数据的仓库.
    主要区别:
    (1)数据库是面向事务的设计,数据仓库是面向主题设计的。
    (2)数据库一般存储在线交易数据,数据仓库存储的一般是历史数据。
    (3)数据库设计是尽量避免冗余,数据仓库在设计是有意引入冗余。
    (4)数据库是为捕获数据而设计,数据仓库是为分析数据而设计。
    ps:不仅理解概念并能给出自己的理解加分
  3. 谈谈你对对象关系型映射(orm)的理解。
    Object Relational Mapping 简称orm,从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.
    orm的优点与缺点:
    首先,ORM最大的优势。
    隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。

    第二:ORM使我们构造固化数据结构变得简单易行。
    在ORM年表的史前时代,我们需要将我们的对象模型转化为一条一条的SQL语句,通过直连或是DB helper在关系数据库构造我们的数据库体系。而现在,基本上所有的ORM框架都提供了通过对象模型构造关系数据库结构的功能。
    ps:如能说出来以上意思并说出为什么需要orm加分

  4. 区分进程和线程。
    答出什么是进程,什么是线程合格,进一步说出进程的组成以及线程的基本情况加分
  5. 请用一个例子表明全局对象的缺点。
    使用全局对象具有如下缺点:
    • 使用全局对象的函数依赖于全局对象的存在和类型,这使得在不同上下文环境中重用该函数更加困难
    • 如果程序必须被修改,则全局依赖增加了引入错误的可能性,而且既使只对局部做修改也要求程序员必须理解整个程序
    • 如果全局对象得到一个不正确的值,则必须查找整个程序以判断错误发生的位置
    • 当一个函数使用全局对象时,递归更加难以正确完成,递归在程序调用自身时才发生
    • 在线程存在的情况下,我们必须做特殊的编码,以便同步各个线程对于全局对象的读和写操作
    ps:例子不限,体现其中一点

  6. 区分 stringbuffer 与 Stringbuilder。

    1. 在执行速度方面的比较:StringBuilder > StringBuffer
    2. StringBuffer与StringBuilder,他们是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,实际上是在一个对象上操作的,不像String一样创建一些对象进行操作,所以速度就快了。
    3. StringBuilder:线程非安全的
        StringBuffer:线程安全的
      当我们在字符串缓冲去被多个线程使用是,JVM不能保证StringBuilder的操作是安全的,虽然他的速度最快,但是可以保证StringBuffer是可以正确操作的。当然大多数情况下就是我们是在单线程下进行的操作,所以大多数情况下是建议用StringBuilder而不用StringBuffer的,就是速度的原因。

对于三者使用的总结:1.如果要操作少量的数据用 = String
       2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
       3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
7. 谈谈你对 TCP 三次握手中 TIME_WAIT 和 CLOSE_WAIT 状态的理解。
TIME_WAIT:表示主动关闭,通过优化系统内核参数可容易解决。
CLOSE_WAIT:表示被动关闭,需要从程序本身出发。
TIME_WAIT:TIME_WAIT是主动关闭连接的一方保持的状态,对于服务器来说它本身就是“客户端”,在完成一个爬取任务之后,它就会发起主动关闭连接,从而进入TIME_WAIT的状态,然后在保持这个状态2MSL(max segment lifetime)时间之后,彻底关闭回收资源。为什么要这么做?明明就已经主动关闭连接了为啥还要保持资源一段时间呢?这个是TCP/IP的设计者规定的,主要出于以下两个方面的考虑:
防止上一次连接中的包,迷路后重新出现,影响新连接(经过2MSL,上一次连接中所有的重复包都会消失)
可靠的关闭TCP连接。在主动关闭方发送的最后一个 ack(fin) ,有可能丢失,这时被动方会重新发fin, 如果这时主动方处于 CLOSED 状态 ,就会响应 rst 而不是 ack。所以主动方要处于 TIME_WAIT 状态,而不能是 CLOSED 。另外这么设计TIME_WAIT 会定时的回收资源,并不会占用很大资源的,除非短时间内接受大量请求或者受到攻击。
CLOSE_WAIT:
TCP协议规定,对于已经建立的连接,网络双方要进行四次握手才能成功断开连接,如果缺少了其中某个步骤,将会使连接处于假死状态,连接本身占用的资源不会被释放。网络服务器程序要同时管理大量连接,所以很有必要保证无用连接完全断开,否则大量僵死的连接会浪费许多服务器资源.
8. 简述在 epoll的水平触发下,当socket可写的时候,会不停的触发写事件的原因。
evel_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率.
ps:由于水平触发的特性,所以就会造成这种情况,这是我个人的理解,具体网上也没有一个具体答案,面试时根据实际情况
9. 简述打开TCP套接字有很大开销的原因。
当一个soket打开时,接着会调用bind()->listen()->accept() 为了执行一个I/O,一个进程必须做的第一件事情就是调用socket函数,指定期望的通信协议类型,Socket函数在成功时返回一个套接字描述符(sockfd),它唯一标识一个socket。这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作。 TCP客户用connect函数来与服务器建立连接。第一个参数是socket函数返回的套接字描述符,第二个、第三个参数分别是一个指向套接字地址结构的指针和该结构的大小。客户在调用函数connect前不必非得调用bind函数,因为如果需要的话,内核会确定源IP地址,并选择一个临时端口作为源端口。
调用connect函数将激发TCP的三次握手过程,而且仅在连接建立成功或者出错时才返回。当我们调用socket函数时,返回的socket描述字它存在于协议族中,但没有一个具体的地址。如果想要给它赋值一个地址,就必须调用bind函数,否则系统会自动随机分配一个端口。 listen函数仅由TCP服务器调用,当socket函数创建一个套接字时,它被假设为一个主动套接字。而listen函数的作用就是把一个未连接套接字转换成一个被动套接字,指示内核应接受指向该套接字的连接请求,即将该套接字从CLOSED状态转换到LISTEN状态。所以这一系列的操作导致打开一个socket套接字有很大的开销。
ps:答出部分即可

10. 以下两道编程题二选一,全做加分。
10.1. 使用信号量实现有限缓冲区的生产者和消费者问题。

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <time.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include <sys/sem.h>
  7. #include <sys/shm.h>
  8. #include <sys/stat.h>
  9. #define REPEATS (10)
  10. #define MAX_BUFFER_SIZE (8)
  11. typedef struct
  12. {
  13. int bottom;
  14. int top;
  15. int data[MAX_BUFFER_SIZE];
  16. } STRUCT_BUFFER;
  17. STRUCT_BUFFER * pBuffer = NULL;
  18. #define PRODUCER_SPEED (1)
  19. #define CONSUMER_SPEED (2)
  20. int sem_consume;
  21. int sem_produce;
  22. int shm_buffer;
  23. #define FLAG (IPC_CREAT | S_IRWXU)
  24. void init()
  25. {
  26. union semun {
  27. int val;
  28. struct semid_ds *buf;
  29. unsigned short *array;
  30. } arg;
  31. shm_buffer = shmget(0x1111, sizeof(STRUCT_BUFFER), FLAG);
  32. pBuffer = shmat(shm_buffer, 0, 0);
  33. memset(pBuffer, 0, sizeof(STRUCT_BUFFER));
  34. sem_consume = semget(0x2222, 1, FLAG);
  35. arg.val = 0;
  36. if (semctl(sem_consume, 0, SETVAL, arg) < 0)
  37. {
  38. perror("Consumer");
  39. exit(1);
  40. }
  41. sem_produce = semget(0x3333, 1, FLAG);
  42. arg.val = MAX_BUFFER_SIZE;
  43. if (semctl(sem_produce, 0, SETVAL, arg) < 0)
  44. {
  45. perror("Producer");
  46. exit(1);
  47. }
  48. }
  49. void deinit()
  50. {
  51. shmctl(shm_buffer, IPC_RMID, NULL);
  52. semctl(sem_consume, 0, IPC_RMID);
  53. semctl(sem_produce, 0, IPC_RMID);
  54. }
  55. int main()
  56. {
  57. int pid, i;
  58. struct sembuf sbuf;
  59. init();
  60. printf("Start fork...\n");
  61. pid = fork();
  62. if (pid > 0)
  63. {
  64. for (i = 0; i < REPEATS; i++)
  65. {
  66. sbuf.sem_num=0;
  67. sbuf.sem_op=-1;
  68. sbuf.sem_flg=0;
  69. semop(sem_consume, &sbuf, 1);
  70. printf("Consumer get %6d\n", pBuffer->data[pBuffer->bottom]);
  71. pBuffer->bottom = (pBuffer->bottom+1)%MAX_BUFFER_SIZE;
  72. sbuf.sem_op = 1;
  73. semop(sem_produce, &sbuf, 1);
  74. sleep(CONSUMER_SPEED);
  75. }
  76. wait(0);
  77. shmdt(pBuffer);
  78. }
  79. else if (pid == 0)
  80. {
  81. srand(time(NULL));
  82. for (i = 0; i < REPEATS; i++)
  83. {
  84. sbuf.sem_num=0;
  85. sbuf.sem_op=-1;
  86. sbuf.sem_flg=0;
  87. semop(sem_produce, &sbuf, 1);
  88. pBuffer->data[pBuffer->top] = (rand()%1000)*1000 + i + 1;
  89. printf("Producer put %6d\n", pBuffer->data[pBuffer->top]);
  90. pBuffer->top = (pBuffer->top+1)%MAX_BUFFER_SIZE;
  91. sbuf.sem_op = 1;
  92. semop(sem_consume, &sbuf, 1);
  93. sleep(PRODUCER_SPEED);
  94. }
  95. shmdt(pBuffer);
  96. exit(0);
  97. }
  98. deinit();
  99. return 0;
  100. }

10.2. 搭建开发环境,本地环境用 Post 方法向后台发送 Json 数据。如果是以下内容则返回“Happy 5 Anniversary!”,否则返回“error”(可用 postman 谷歌浏览器插件插件模拟请求)。
```
{
name: “CreatShare”
anniversary: 5,
year: 2016
}

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注