@yiranblade
2016-10-21T07:38:45.000000Z
字数 5147
阅读 296
未分类
谈谈你对对象关系型映射(orm)的理解。
Object Relational Mapping 简称orm,从效果上说,它其实是创建了一个可在编程语言里使用的“虚拟对象数据库”。 是一种程序设计技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换.
orm的优点与缺点:
首先,ORM最大的优势。
隐藏了数据访问细节,“封闭”的通用数据库交互,ORM的核心。他使得我们的通用数据库交互变得简单易行,并且完全不用考虑该死的SQL语句。快速开发,由此而来。
第二:ORM使我们构造固化数据结构变得简单易行。
在ORM年表的史前时代,我们需要将我们的对象模型转化为一条一条的SQL语句,通过直连或是DB helper在关系数据库构造我们的数据库体系。而现在,基本上所有的ORM框架都提供了通过对象模型构造关系数据库结构的功能。
ps:如能说出来以上意思并说出为什么需要orm加分
请用一个例子表明全局对象的缺点。
使用全局对象具有如下缺点:
• 使用全局对象的函数依赖于全局对象的存在和类型,这使得在不同上下文环境中重用该函数更加困难
• 如果程序必须被修改,则全局依赖增加了引入错误的可能性,而且既使只对局部做修改也要求程序员必须理解整个程序
• 如果全局对象得到一个不正确的值,则必须查找整个程序以判断错误发生的位置
• 当一个函数使用全局对象时,递归更加难以正确完成,递归在程序调用自身时才发生
• 在线程存在的情况下,我们必须做特殊的编码,以便同步各个线程对于全局对象的读和写操作
ps:例子不限,体现其中一点
区分 stringbuffer 与 Stringbuilder。
对于三者使用的总结: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. 使用信号量实现有限缓冲区的生产者和消费者问题。
#include <stdio.h>#include <unistd.h>#include <time.h>#include <string.h>#include <stdlib.h>#include <sys/sem.h>#include <sys/shm.h>#include <sys/stat.h>#define REPEATS (10)#define MAX_BUFFER_SIZE (8)typedef struct{int bottom;int top;int data[MAX_BUFFER_SIZE];} STRUCT_BUFFER;STRUCT_BUFFER * pBuffer = NULL;#define PRODUCER_SPEED (1)#define CONSUMER_SPEED (2)int sem_consume;int sem_produce;int shm_buffer;#define FLAG (IPC_CREAT | S_IRWXU)void init(){union semun {int val;struct semid_ds *buf;unsigned short *array;} arg;shm_buffer = shmget(0x1111, sizeof(STRUCT_BUFFER), FLAG);pBuffer = shmat(shm_buffer, 0, 0);memset(pBuffer, 0, sizeof(STRUCT_BUFFER));sem_consume = semget(0x2222, 1, FLAG);arg.val = 0;if (semctl(sem_consume, 0, SETVAL, arg) < 0){perror("Consumer");exit(1);}sem_produce = semget(0x3333, 1, FLAG);arg.val = MAX_BUFFER_SIZE;if (semctl(sem_produce, 0, SETVAL, arg) < 0){perror("Producer");exit(1);}}void deinit(){shmctl(shm_buffer, IPC_RMID, NULL);semctl(sem_consume, 0, IPC_RMID);semctl(sem_produce, 0, IPC_RMID);}int main(){int pid, i;struct sembuf sbuf;init();printf("Start fork...\n");pid = fork();if (pid > 0){for (i = 0; i < REPEATS; i++){sbuf.sem_num=0;sbuf.sem_op=-1;sbuf.sem_flg=0;semop(sem_consume, &sbuf, 1);printf("Consumer get %6d\n", pBuffer->data[pBuffer->bottom]);pBuffer->bottom = (pBuffer->bottom+1)%MAX_BUFFER_SIZE;sbuf.sem_op = 1;semop(sem_produce, &sbuf, 1);sleep(CONSUMER_SPEED);}wait(0);shmdt(pBuffer);}else if (pid == 0){srand(time(NULL));for (i = 0; i < REPEATS; i++){sbuf.sem_num=0;sbuf.sem_op=-1;sbuf.sem_flg=0;semop(sem_produce, &sbuf, 1);pBuffer->data[pBuffer->top] = (rand()%1000)*1000 + i + 1;printf("Producer put %6d\n", pBuffer->data[pBuffer->top]);pBuffer->top = (pBuffer->top+1)%MAX_BUFFER_SIZE;sbuf.sem_op = 1;semop(sem_consume, &sbuf, 1);sleep(PRODUCER_SPEED);}shmdt(pBuffer);exit(0);}deinit();return 0;}
10.2. 搭建开发环境,本地环境用 Post 方法向后台发送 Json 数据。如果是以下内容则返回“Happy 5 Anniversary!”,否则返回“error”(可用 postman 谷歌浏览器插件插件模拟请求)。
```
{
name: “CreatShare”
anniversary: 5,
year: 2016
}