09年的百度面试

一面

1.网络编程经验:

   如何判断一个客户端http请求已经结束?客户端程序如何判断服务端的应答是否已结束?如何处理服务器多线程?(这题可以从我自己以前的那个项目寻求结果!!!)

答:首部的结束是以连续两个新行标记(\r\n)来表示的,有了首部之后:

       http请求参考http://blog.csdn.net/kfanning/article/details/6062118

(1) 根据头中的Content-Length字段。这个字段标明了正文的长度,我们可以以接收完指定长度的字符为判断结束的依据。
(2) 在没有Content-Length时,根据Transfer-Encoding。有些时候服务器无法确定正文的大小,因为正文可能是动态产生的,所以就不会提供Content-Length了,而是采用chunk编码来一块一块地发送正文。每个chunk块由头部和正文两部分组成,头部中由一个16进制数字指定了正文的长度(头和正文以\r\n分开);最后由一个长度为0的chunk块来表示整个HTTP正文的结束。
      chunk参考:http://blog.csdn.net/zztfj/article/details/5906168
    
大型服务器肯定是链接池,保持N个并发连接不动,来了连接请求就用其中一个链接来响应.

线程池????????????????????????????????????????

qq服务器是linux,多台服务器集群处理,每台开辟大量的线程池进行请求处理,采用的是事件模型,具体是epoll,像上面说的处理大量连接的C10k问题。像百度,腾讯等服务器一般都是linux,自己定制内核,使性能最优。技术很复杂的,你搞清楚了,离大牛也不远了。



大型服务器肯定是链接池,保持N个并发连接不动,来了连接请求就用其中一个链接来响应

   获得一个http请求后,是如何处理的?返回什么?有没有试过返回图片?
   服务器给客户端请求时,是用什么函数写?服务器如何获取客户端请求,用什么函数
   (需要函数级别的连接有一个认识)

2. cv操作是什么函数 cv_init, cv_wait, cv_signal

(条件变量(Condition variables) 条件变量构建于互斥体之上,和互斥体联合使用,等待条件发生。我们可以理解为基于锁的msleep机制(参考:msleep(Array))。)


3. 有一些关键词点击次数的文件,如何输出最多点击的一百个(当时应该回答,组织一个100个元素的最大堆)

4. 相交链表,如何找相交点(不能要标记)
   第一个头遍历到尾,知道他的长度;第二个头遍历到尾,知道他的长度。这样知道两截链表在交点前的长度,长的先走几步,然后一样长了,再轮流下走,就会相聚,相遇节点就是相交节点)

5. 有些文件,频繁访问在磁盘里头的,现在要放到内存中了。采用什么策略来决定哪些放到内存中?如果是一些url文件,放在内存后,如何快速的找到某个url的位置(采用字典序或者b树之类树状结构来组织) 如何快速找到哪些文件太久没人访问了,把他替换出去?(再那一棵树,记录树里每个位置url的访问时间;同时,那个url树的节点,也有这个时间树的对应的位置信息。时间树采用最大堆组织。要替换出去时,就从树顶取走节点,并且从中获得这个节点在url树对应位置,把他从url树中取走。当url被访问时,由于url树节点有时间树的位置信息,所以也很快找到对应节点在时间树的位置,然后把他的访问时间更新,然后做堆调整,每次堆调整为logN)

6. c语言相关:内联函数的好处?非内联函数被调用的过程是怎么样的?
   int,short,char的struct,这几个数应该怎么放,内存大小?怎么防止头文件被include多次?






为了避免同一个文件被include多次:
1   #ifndef方式
2   #pragma once方式

在能够支持这两种方式的编译器上,二者并没有太大的区别,但是两者仍然还是有一些细微的区别。
    方式一:

    #ifndef __SOMEFILE_H__
    #define __SOMEFILE_H__
    ... ... // 一些声明语句
    #endif

    方式二:

    #pragma once
    ... ... // 一些声明语句


    #ifndef的方式依赖于宏名字不能冲突,这不光可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件不会被不小心同时包含。当然,缺点就是如果不同头文件的宏名不小心“撞车”,可能就会导致头文件明明存在,编译器却硬说找不到声明的状况

    #pragma once则由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。带来的好处是,你不必再费劲想个宏名了,当然也就不会出现宏名碰撞引发的奇怪问题。对应的缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名碰撞引发的“找不到声明”的问题,重复包含更容易被发现并修正。

   方式一由语言支持所以移植性好,方式二 可以避免名字冲突。

一般可以这样处理:

#ifndef XX
#define XX
     #if _MSC_VER > 1000  
       #pragma once 
    #endif
     .
     .
#endif

7 linux 网络查看的命令

二面
1. 介绍一个项目

2. 2.5亿个int数,可能有相同的。统计出这里头不同的数有多少个?只有2g内存。
(2.5*1000 000 000 * 4 =1G)
统计数-用hash,key是数,value是1或0,标记是否出现。
如果key就是那个数,那么找一个数的时候,要遍历hash才知道有没有,慢(就是如果hash紧凑,慢)。
解决方案:把key作为连续的(就是hash是稀疏的,有个key值没有存在这2.5亿个数中),像数组下标一样,那么要访问第n个数,直接到第n个去看,复杂度是O(1)
但是,如果连续,2.5亿个数,范围很广,而每个key用int存,会很大量,内存不一定够。
解决方案:每个key用一位bit来标志。即数字1放在第一个bit上,数字2放在第二个bit上。看第n位在不在,就找一下第n个bit是1,还是0
具体方法:char a[] 数组。假设找3,那么3在3/8--0...3,所以在a[0]中,找第3个bit,如果是0,就设置为1。最后看看a[]的二进制表示有多少个1就有多少个数

3. 海量数据,在mysql中,cpu占用率很高。如何解决?
1.show processlist,看哪个sql查询的多,建索引(问:建立联合索引时,要考虑什么,怎么建(哪个在前,哪个列在后?)
2.如果老是在拷贝到临时表,就改配置,把临时表内存改大些
3.还有什么方法:
1)分布式数据库 (问:如果你来设计分布式数据库,你会怎么设计?)
2)使用缓存   (问:如果缓存中的数据,被删除或跟新了,数据库怎么判断这个缓存的数据不能用了,是脏数据?)(不懂)
问:什么情况下cpu会高?(内存不足)为什么内存不足cpu会高(频繁io读写)

4. n个无序int,(有正有负),给一个数v,如何找出其中的a+b=v的两个数
(我的答案是:排序 O(nlogn),记录序列中,0,大于v,小于v的3位。
尝试最小的和最大的,最大不行,次大。。。,找到某个,加起来小于v了,停止
尝试次小的,从上次大头停止的位置开始尝试
---尝试范围两头不断缩小,复杂度为n)

5. 网络相册,一个人可以有多个相册,一个相册有多个图片,如何快速实现增删查移动等操作。web页面上,图片是翻页显示。
(我回答:数据库记录:usr_id, book_id, item_id, position。相片放在磁盘上,目录为position/usr_id/book_id/item_id
一次查两个操作:1)数据库查找2)根据位置取图片

如果用户提取某个相册的所有图片,先给他第一个相片和所有item_id列表。然后用户翻页了,在客户端通过javascript能够知道翻的是哪个item,把item_id,book_id, usr_id发给服务器,服务器根据这个到目录下去找)
(你这种设计会有什么问题?(答不上来。。。)(如果用户频繁翻页,那么服务器上会不断地在传输图片)(如何解决?)

第五题我想不出好办法,我觉得一般他们都show thumbnail
就是预览小图片不把原始图片show在页面上,点击后才能看单个图片


6. Unix系统里,一个简单的print hello world的c程序,从./a.out执行到屏幕打印出来这句话,是什么过程
(1.读elf,会从相对地址,计算出各个symbol的在进程中的绝对地址。然后找到入口main函数
  1.用到std的库,所有有run time load。
  2.然后是print调用的进栈
  3.然后是系统调用,当前进程被挂起。系统调用会调用驱动。。。(内核切换,用户态到内核态)
  4.内核处理完再唤醒当前进程。(切换)
  5.print调用完毕,退栈
  6.main函数退栈

问:哪个进程来调用的main?(不知道)
应该是当前运行a.out的这个和用户交互的shell作为父进程,然后父进程fork子进程,子进程和父进程一样,然后调用execv会load执行文件,和把参数传到main的堆栈中

7.socket编程,要注意什么问题
(服务器的serversocket的基本模型。
但是大量请求,会不能及时响应。所以要多线程。
一个监听线程,多个服务线程。服务线程一开始起来都阻塞在存放请求socket的tasklist上。wait
监听线程接受到client的socket,放入tasklist中,signal唤醒一个服务线程。服务线程处理它,并把它从list中移走
注意问题:tasklist的存放的请求socket是会被放和移走的,消费者生产者问题。所以要synchronized来互斥?)

三面
2. fread的过程(文件系统-内核。。。)
3. 主DB在接到数据更新后同步到后台DB,如何避免网络丢失之类的问题
(参考答案1:传的是sql语句,接到后回ack,如果主DB发现一段时间没有回,重发;其实TCP传输,就保证了不会漏数据,所以不会考虑这个问题的)
(参考答案2:每次传sql语句和当前版本号,然后后台DB会对比版本号是不是正确,发现落后就发数据请求。主DB保留每次版本号更新关联的sql语句)
4. N个bit,如和判断其中有多少个1.(时间复杂度小于N)
预存一个2的8次方大小的数组,每个数组值是,这个下标的数的二进制的1的个数,例如:
a[0]=0, a[1]=1, a[2]=1,a[3]=2....a[2^8-1]=7 (以空间换时间)

然后一个byte一个byte的读,看看他的值,直接以这个值为下标去数组看他的1的个数


另一个方法:

while(v){
v &= (v-1);
num++;
}
1000 & 0111 = 0, 所以每&一次,不为0,说明有1个1,&到为0为止,num就是1的个数。复杂度为1的个数。

你可能感兴趣的:(数据库,面试,百度,服务器,url,相册)