騰訊後臺開發筆試知識點彙總

linux和os:
netstat :顯示網絡狀態


tcpdump:主要是截獲通過本機網絡接口的數據,用以分析。能夠截獲當前所有通過本機網卡的數據包。它擁有靈活的過濾機制,可以確保得到想要的數據。
ipcs:檢查系統上共享內存的分配
ipcrm:手動解除系統上共享內存的分配
(如果這四個命令沒聽說過或者不能熟練使用,基本上可以回家,通過的概率較小 ^_^ ,這四個命令的熟練掌握程度基本上能體現面試者實際開發和調試程序的經驗)
cpu 內存 硬盤 等等與系統性能調試相關的命令必須熟練掌握,設置修改權限 tcp網絡狀態查看 各進程狀態 抓包相關等相關命令 必須熟練掌握
 
(一)查看CPU信息 
使用下面的指令,就可以查看到CPU的詳細信息了。一般來講,多核的CPU,或者支持超線程的CPU,或者物理上的多個CPU,就會顯示出對應的條數的信息。比如說雙核的CPU就會顯示2條CPU信息,雙核超線程的CPU就會顯示出4條CPU信息。雖然條數多了,但是基本信息都一樣。  
#cat /proc/cpuinfo 
(二)查看內存信息 
與查看CPU信息對應的,查看內存信息的命令就是: 
#cat /proc/meminfo  
(三)查看硬盤分區信息 
使用下面的命令,可以看到當前硬盤的分區信息,以及容量大小、已使用的空間和剩餘空間大小,還可以查看每個分區的掛載點: 
#df -lh   www.2cto.com  
(四)查看硬盤的型號信息 
可以使用下面的命令顯示物理硬盤的個數以及對應的接口,還有硬盤的具體型號信息: 
#cat /proc/scsi/scsi 
以上的信息的具體解釋,可以參考網絡上的相關文章,這裏就不再詳細描述。這些指令在所有的Linux下均是通用的。
http://blog.chinaunix.net/uid-15007890-id-106937.html
awk sed需掌握
共享內存的使用實現原理(必考必問,然後共享內存段被映射進進程空間之後,存在於進程空間的什麼位置?共享內存段最大限制是多少?)
共享內存定義:共享內存是最快的可用IPC(進程間通信)形式。它允許多個不相關的進程去訪問同一部分邏輯內存。共享內存是由IPC爲一個進程創建的一個特殊的地址範圍,它將出現在進程的地址空間中。其他進程可以把同一段共享內存段“連接到”它們自己的地址空間裏去。所有進程都可以訪問共享內存中的地址。如果一個進程向這段共享內存寫了數據,所做的改動會立刻被有訪問同一段共享內存的其他進程看到。因此共享內存對於數據的傳輸是非常高效的。
共享內存的原理:共享內存是最有用的進程間通信方式之一,也是最快的IPC形式。兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。
c++進程內存空間分佈(注意各部分的內存地址誰高誰低,注意棧從高到低分配,堆從低到高分配)
ELF是什麼?其大小與程序中全局變量的是否初始化有什麼關係(注意未初始化的數據放在bss段)
可執行文件:包含了代碼和數據。具有可執行的程序。
可重定位文件:包含了代碼和數據(這些數據是和其他重定位文件和共享的
object文件一起連接時使用的)
共享object文件(又可叫做共享庫):包含了代碼和數據(這些數據是在連接
時候被連接器ld和運行時動態連接器使用的)。
使創建共享庫容易,使動態裝載和共享庫的結合更加容易。在ELF下,在C++
中,全局的構造函數和析構函數在共享庫和靜態庫中用同樣方法處理。
使用過哪些進程間通訊機制,並詳細說明(重點)
makefile編寫,雖然比較基礎,但是會被問到
mkdir mf
cd mf
vim makefile
hello.o:hello.c hello.h
     gcc –c hello.o -Lm
make
./hello
gdb調試相關的經驗,會被問到
如何定位內存泄露?
內存泄漏是指堆內存的泄漏。堆內存是指程序從堆中分配的、大小任意的(內存塊的大小可以在程序運行期決定)、使用完後必須顯示釋放的內存。應用程序一般使用malloc、realloc、new等函數從堆中分配到一塊內存,使用完後,程序必須負責相應的調用free或delete釋放該內存塊。否則,這塊內存就不能被再次使用,我們就說這塊內存泄漏了。
C++程序缺乏相應的手段來檢測內存信息,只能使用top指令觀察進程的動態內存總額。而且程序退出時,我們無法獲知任何內存泄漏信息
使用Linux命令回收內存,可以使用ps、kill兩個命令檢測內存使用情況和進行回收。在使用超級用戶權限時使用命令“ps”,它會列出所有正在運行的程序名稱和對應的進程號(PID)。kill命令的工作原理是向Linux操作系統的內核送出一個系統操作信號和程序的進程號(PID)
動態鏈接和靜態鏈接的區別
動態鏈接是指在生成可執行文件時不將所有程序用到的函數鏈接到一個文件,因爲有許多函數在操作系統帶的dll文件中,當程序運行時直接從操作系統中找。 而靜態鏈接就是把所有用到的函數全部鏈接到exe文件中。
動態鏈接是隻建立一個引用的接口,而真正的代碼和數據存放在另外的可執行模塊中,在運行時再裝入;而靜態鏈接是把所有的代碼和數據都複製到本模塊中,運行時就不再需要庫了。
32位系統一個進程最多有多少堆內存
多線程和多進程的區別(重點 面試官最最關心的一個問題,必須從cpu調度,上下文切換,數據共享,多核cup利用率,資源佔用,等等各方面回答,然後有一個問題必須會被問到:哪些東西是一個線程私有的?答案中必須包含寄存器,否則悲催)
寫一個c程序辨別系統是16位or32位
法一:int k=~0;
if((unsigned int)k >63356) cout<<"at least 32 bits"<<endl;
else cout<<"16 bits"<<endl;
法二://32爲系統
int i=65536;
cout<<i<<endl;
int j=65535;
cout<<j<<endl;
寫一個c程序辨別系統是大端or小端字節序
用聯合體:如char類型的,可以看他輸出的是int的高字節還是低字節
信號:列出常見的信號,信號怎麼處理?
i++是否原子操作?並解釋爲什麼?
說出你所知道的linux系統的各類同步機制(重點),什麼是死鎖?如何避免死鎖(每個技術面試官必問)
死鎖的條件。(互斥條件(Mutual exclusion):1、資源不能被共享,只能由一個進程使用。2、請求與保持條件(Hold and wait):已經得到資源的進程可以再次申請新的資源。3、非剝奪條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。4、循環等待條件(Circular wait):系統中若干進程組成環路,該環路中每個進程都在等待相鄰進程正佔用的資源。處理死鎖的策略:1.忽略該問題。例如鴕鳥算法,該算法可以應用在極少發生死鎖的的情況下。爲什麼叫鴕鳥算法呢,因爲傳說中鴕鳥看到危險就把頭埋在地底下,可能鴕鳥覺得看不到危險也就沒危險了吧。跟掩耳盜鈴有點像。2.檢測死鎖並且恢復。3.仔細地對資源進行動態分配,以避免死鎖。4.通過破除死鎖四個必要條件之一,來防止死鎖產生。)
列舉說明linux系統的各類異步機制
exit()與_exit()的區別?
_exit終止調用進程,但不關閉文件,不清除輸出緩存,也不調用出口函數。exit函數將終止調用進程。在退出程序之前,所有文件關閉,緩衝輸出內容將刷新定義,並調用所有已刷新的“出口函數”(由atexit定義)。
‘exit()’與‘_exit()’有不少區別在使用‘fork()’,特別是‘vfork()’時變得很突出。
‘exit()’與‘_exit()’的基本區別在於前一個調用實施與調用庫裏用戶狀態結構(user-mode constructs)有關的清除工作(clean-up),而且調用用戶自定義的清除程序
如何實現守護進程?
守護進程(Daemon)是運行在後臺的一種特殊進程。它獨立於控制終端並且週期性地執行某種任務或等待處理某些發生的事件。守護進程是一種很有用的進程。 Linux的大多數服務器就是用守護進程實現的。比如,Internet服務器inetd,Web服務器httpd等。同時,守護進程完成許多系統任務。比如,作業規劃進程crond,打印進程lpd等。
守護進程的編程本身並不複雜,複雜的是各種版本的Unix的實現機制不盡相同,造成不同 Unix環境下守護進程的編程規則並不一致。需要注意,照搬某些書上的規則(特別是BSD4.3和低版本的System V)到Linux會出現錯誤的。下面將給出Linux下守護進程的編程要點和詳細實例。
一. 守護進程及其特性
守護進程最重要的特性是後臺運行。在這一點上DOS下的常駐內存程序TSR與之相似。其次,守護進程必須與其運行前的環境隔離開來。這些環境包括未關閉的文件描述符,控制終端,會話和進程組,工作目錄以及文件創建掩模等。這些環境通常是守護進程從執行它的父進程(特別是shell)中繼承下來的。最後,守護進程的啓動方式有其特殊之處。它可以在Linux系統啓動時從啓動腳本/etc/rc.d中啓動,可以由作業規劃進程crond啓動,還可以由用戶終端(shell)執行。
總之,除開這些特殊性以外,守護進程與普通進程基本上沒有什麼區別。因此,編寫守護進程實際上是把一個普通進程按照上述的守護進程的特性改造成爲守護進程。如果對進程有比較深入的認識就更容易理解和編程了。
二. 守護進程的編程要點
前面講過,不同Unix環境下守護進程的編程規則並不一致。所幸的是守護進程的編程原則其實都一樣,區別在於具體的實現細節不同。這個原則就是要滿足守護進程的特性。同時,Linux是基於Syetem V的SVR4並遵循Posix標準,實現起來與BSD4相比更方便。編程要點如下;
1. 在後臺運行。
爲避免掛起控制終端將Daemon放入後臺執行。方法是在進程中調用fork使父進程終止,讓Daemon在子進程中後臺執行。
if(pid=fork())
exit(0); //是父進程,結束父進程,子進程繼續
2. 脫離控制終端,登錄會話和進程組
有必要先介紹一下Linux中的進程與控制終端,登錄會話和進程組之間的關係:進程屬於一個進程組,進程組號(GID)就是進程組長的進程號(PID)。登錄會話可以包含多個進程組。這些進程組共享一個控制終端。這個控制終端通常是創建進程的登錄終端。控制終端,登錄會話和進程組通常是從父進程繼承下來的。我們的目的就是要擺脫它們,使之不受它們的影響。方法是在第1點的基礎上,調用setsid()使進程成爲會話組長:
setsid();
說明:當進程是會話組長時setsid()調用失敗。但第一點已經保證進程不是會話組長。setsid()調用成功後,進程成爲新的會話組長和新的進程組長,並與原來的登錄會話和進程組脫離。由於會話過程對控制終端的獨佔性,進程同時與控制終端脫離。
3. 禁止進程重新打開控制終端
現在,進程已經成爲無終端的會話組長。但它可以重新申請打開一個控制終端。可以通過使進程不再成爲會話組長來禁止進程重新打開控制終端:
if(pid=fork()) exit(0); //結束第一子進程,第二子進程繼續(第二子進程不再是會話組長)
4. 關閉打開的文件描述符
進程從創建它的父進程那裏繼承了打開的文件描述符。如不關閉,將會浪費系統資源,造成進程所在的文件系統無法卸下以及引起無法預料的錯誤。按如下方法關閉它們:
for(i=0;i 關閉打開的文件描述符close(i);>
5. 改變當前工作目錄
進程活動時,其工作目錄所在的文件系統不能卸下。一般需要將工作目錄改變到根目錄。對於需要轉儲核心,寫運行日誌的進程將工作目錄改變到特定目錄如 /tmpchdir("/")
6. 重設文件創建掩模
進程從創建它的父進程那裏繼承了文件創建掩模。它可能修改守護進程所創建的文件的存取位。爲防止這一點,將文件創建掩模清除:umask(0);
7. 處理SIGCHLD信號
處理SIGCHLD信號並不是必須的。但對於某些進程,特別是服務器進程往往在請求到來時生成子進程處理請求。如果父進程不等待子進程結束,子進程將成爲殭屍進程(zombie)從而佔用系統資源。如果父進程等待子進程結束,將增加父進程的負擔,影響服務器進程的併發性能。在Linux下可以簡單地將 SIGCHLD信號的操作設爲SIG_IGN。
signal(SIGCHLD,SIG_IGN);
這樣,內核在子進程結束時不會產生殭屍進程。這一點與BSD4不同,BSD4下必須顯式等待子進程結束才能釋放殭屍進程。
三. 守護進程實例
守護進程實例包括兩部分:主程序test.c和初始化程序init.c。主程序每隔一分鐘向/tmp目錄中的日誌test.log報告運行狀態。初始化程序中的init_daemon函數負責生成守護進程。讀者可以利用init_daemon函數生成自己的守護進程。

linux的內存管理機制是什麼?
Linux虛擬內存的實現需要6種機制的支持:地址映射機制、內存分配回收機制、緩存和刷新機制、請求頁機制、交換機制和內存共享機制
內存管理程序通過映射機制把用戶程序的邏輯地址映射到物理地址。當用戶程序運行時,如果發現程序中要用的虛地址沒有對應的物理內存,就發出了請求頁要求。如果有空閒的內存可供分配,就請求分配內存(於是用到了內存的分配和回收),並把正在使用的物理頁記錄在緩存中(使用了緩存機制)。如果沒有足夠的內存可供分配,那麼就調用交換機制;騰出一部分內存。另外,在地址映射中要通過TLB(翻譯後援存儲器)來尋找物理頁;交換機制中也要用到交換緩存,並且把物理頁內容交換到交換文件中,也要修改頁表來映射文件地址。
linux的任務調度機制是什麼?
標準庫函數和系統調用的區別?
1、系統調用和庫函數的關係
系統調用通過軟中斷int 0x80從用戶態進入內核態。
函數庫中的某些函數調用了系統調用。
函數庫中的函數可以沒有調用系統調用,也可以調用多個系統調用。
編程人員可以通過函數庫調用系統調用。
高級編程也可以直接採用int 0x80進入系統調用,而不必通過函數庫作爲中介。
如果是在覈心編程,也可以通過int 0x80進入系統調用,此時不能使用函數庫。因爲函數庫中的函數是內核訪問不到的。
2、從用戶調用庫函數到系統調用執行的流程。
1) 假設用戶調用ssize_t write (int fields, cont void *buff, size_t nbytes);庫函數。
2) 庫函數會執行int 0x80中斷。因爲中斷使得進程從用戶態進入內核態,所以參數通過寄存器傳送。
3) 0x80中斷對應的中斷例程被稱爲system call handler。其工作是:
i.  存儲大多數寄存器到內核堆棧中。這是彙編代碼寫的。
ii.  執行真正的系統調用函數――system call service routine。這是C代碼。
iii. 通過ret_from_sys_call ()返回,回到用戶態的庫函數。這是彙編代碼。
1、系統調用
系統調用提供的函數如open, close, read, write, ioctl等,需包含頭文件unistd.h。以write爲例:其函數原型爲 size_t write(int fd, const void *buf, size_t nbytes),其操作對象爲文件描述符或文件句柄fd(file descriptor),要想寫一個文件,必須先以可寫權限用open系統調用打開一個文件,獲得所打開文件的fd,例如 fd=open(/"/dev/video/", O_RDWR)。fd是一個整型值,每新打開一個文件,所獲得的fd爲當前最大fd加1。Linux系統默認分配了3個文件描述符值:0-standard input,1-standard output,2-standard error。
系統調用通常用於底層文件訪問(low-level file access),例如在驅動程序中對設備文件的直接訪問。
系統調用是操作系統相關的,因此一般沒有跨操作系統的可移植性。
系統調用發生在內核空間,因此如果在用戶空間的一般應用程序中使用系統調用來進行文件操作,會有用戶空間到內核空間切換的開銷。事實上,即使在用戶空間使用庫函數來對文件進行操作,因爲文件總是存在於存儲介質上,因此不管是讀寫操作,都是對硬件(存儲器)的操作,都必然會引起系統調用。也就是說,庫函數對文件的操作實際上是通過系統調用來實現的。例如C庫函數fwrite()就是通過write()系統調用來實現的。
這樣的話,使用庫函數也有系統調用的開銷,爲什麼不直接使用系統調用呢?這是因爲,讀寫文件通常是大量的數據(這種大量是相對於底層驅動的系統調用所實現的數據操作單位而言),這時,使用庫函數就可以大大減少系統調用的次數。這一結果又緣於緩衝區技術。在用戶空間和內核空間,對文件操作都使用了緩衝區,例如用fwrite寫文件,都是先將內容寫到用戶空間緩衝區,當用戶空間緩衝區滿或者寫操作結束時,纔將用戶緩衝區的內容寫到內核緩衝區,同樣的道理,當內核緩衝區滿或寫結束時纔將內核緩衝區內容寫到文件對應的硬件媒介。
2、庫函數調用
標準C庫函數提供的文件操作函數如fopen, fread, fwrite, fclose, fflush, fseek等,需包含頭文件stdio.h。以fwrite爲例,其函數原型爲size_t fwrite(const void *buffer, size_t size, size_t item_num, FILE *pf),其操作對象爲文件指針FILE *pf,要想寫一個文件,必須先以可寫權限用fopen函數打開一個文件,獲得所打開文件的FILE結構指針pf,例如pf=fopen(/"~/proj/filename/", /"w/")。實際上,由於庫函數對文件的操作最終是通過系統調用實現的,因此,每打開一個文件所獲得的FILE結構指針都有一個內核空間的文件描述符fd與之對應。同樣有相應的預定義的FILE指針:stdin-standard input,stdout-standard output,stderr-standard error。
庫函數調用通常用於應用程序中對一般文件的訪問。
庫函數調用是系統無關的,因此可移植性好。
由於庫函數調用是基於C庫的,因此也就不可能用於內核空間的驅動程序中對設備的操作
ping命令所利用的原理是這樣的:網絡上的機器都有唯一確定的IP地址,我們給目標IP地址發送一個數據包,對方就要返回一個同樣大小的數據包,根據返回的數據包我們可以確定目標主機的存在,可以初步判斷目標主機的操作系統等。
補充一個坑爹坑爹坑爹坑爹的問題:系統如何將一個信號通知到進程?(這一題哥沒有答出來)
c語言:
宏定義和展開(必須精通)
位操作(必須精通)
指針操作和計算(必須精通)
內存分配(必須精通)
sizeof必考
各類庫函數必須非常熟練的實現
哪些庫函數屬於高危函數,爲什麼?(strcpy等等)
c++:
一個String類的完整實現必須很快速寫出來(注意:賦值構造,operator=是關鍵)
虛函數的作用和實現原理(必問必考,實現原理必須很熟)
有虛函數的類內部有一個稱爲“虛表”的指針(有多少個虛函數就有多少個指針),這個就是用來指向這個類虛函數。也就是用它來確定調用該那個函數。
實際上在編譯的時候,編譯器會自動加入“虛表”。虛表的使用方法是這樣的:如果派生類在自己的定義中沒有修改基類的虛函數,就指向基類的虛函數;如果派生類改寫了基類的虛函數(就是自己重新定義),這時虛表則將原來指向基類的虛函數的地址替換爲指向自身虛函數的指針。那些被virtual關鍵字修飾的成員函數,就是虛函數。虛函數的作用,用專業術語來解釋就是實現多態性(Polymorphism),多態性是將接口與實現進行分離;用形象的語言來解釋就是實現以共同的方法,但因個體差異而採用不同的策略。
每個類都有自己的vtbl,vtbl的作用就是保存自己類中虛函數的地址,我們可以把vtbl形象地看成一個數組,這個數組的每個元素存放的就是虛函數的地址,
虛函數的效率低,其原因就是,在調用虛函數之前,還調用了獲得虛函數地址的代碼。

sizeof一個類求大小(注意成員變量,函數,虛函數,繼承等等對大小的影響)
指針和引用的區別(一般都會問到)
相同點:1. 都是地址的概念;
指針指向一塊內存,它的內容是所指內存的地址;引用是某塊內存的別名。
區別:1. 指針是一個實體,而引用僅是個別名;
2. 引用使用時無需解引用(*),指針需要解引用;
3. 引用只能在定義時被初始化一次,之後不可變;指針可變;
4. 引用沒有 const,指針有 const;
5. 引用不能爲空,指針可以爲空;
6. “sizeof 引用”得到的是所指向的變量(對象)的大小,而“sizeof 指針”得到的是指針本身(所指向的變量或對象的地址)的大小;
7. 指針和引用的自增(++)運算意義不一樣;
8.從內存分配上看:程序爲指針變量分配內存區域,而引用不需要分配內存區域。
多重類構造和析構的順序
先調用基類的構造函數,在調用派生類的構造函數
先構造的後析構,後構造的先析構
stl各容器的實現原理(必考)
STL共有六大組件
1、容器。2、算法。3、迭代器。4、仿函數。6、適配器。
序列式容器:
vector-數組,元素不夠時再重新分配內存,拷貝原來數組的元素到新分配的數組中。
list-單鏈表。
deque-分配中央控制器map(並非map容器),map記錄着一系列的固定長度的數組的地址.記住這個map僅僅保存的是數組的地址,真正的數據在數組中存放着.deque先從map中央的位置(因爲雙向隊列,前後都可以插入元素)找到一個數組地址,向該數組中放入數據,數組不夠時繼續在map中找空閒的數組來存數據。當map也不夠時重新分配內存當作新的map,把原來map中的內容copy的新map中。所以使用deque的複雜度要大於vector,儘量使用vector。
stack-基於deque。
queue-基於deque。
heap-完全二叉樹,使用最大堆排序,以數組(vector)的形式存放。
priority_queue-基於heap。
slist-雙向鏈表。
關聯式容器:
set,map,multiset,multimap-基於紅黑樹(RB-tree),一種加上了額外平衡條件的二叉搜索樹。
hash table-散列表。將待存數據的key經過映射函數變成一個數組(一般是vector)的索引,例如:數據的key%數組的大小=數組的索引(一般文本通過算法也可以轉換爲數字),然後將數據當作此索引的數組元素。有些數據的key經過算法的轉換可能是同一個數組的索引值(碰撞問題,可以用線性探測,二次探測來解決),STL是用開鏈的方法來解決的,每一個數組的元素維護一個list,他把相同索引值的數據存入一個list,這樣當list比較短時執行刪除,插入,搜索等算法比較快。
hash_map,hash_set,hash_multiset,hash_multimap-基於hash table。
extern c 是幹啥的,(必須將編譯器的函數名修飾的機制解答的很透徹)
volatile是幹啥用的,(必須將cpu的寄存器緩存機制回答的很透徹)
volatile的本意是“易變的” 因爲訪問寄存器要比訪問內存單元快的多,所以編譯器一般都會作減少存取內存的優化,但有可能會讀髒數據。當要求使用volatile聲明變量值的時候,系統總是重新從它所在的內存讀取數據,即使它前面的指令剛剛從該處讀取過數據。精確地說就是,遇到這個關鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進行優化,從而可以提供對特殊地址的穩定訪問;如果不使用volatile,則編譯器將對所聲明的語句進行優化。(簡潔的說就是:volatile關鍵詞影響編譯器編譯的結果,用volatile聲明的變量表示該變量隨時可能發生變化,與該變量有關的運算,不要進行編譯優化,以免出錯)
5.volatile的本質:
1> 編譯器的優化
在本次線程內, 當讀取一個變量時,爲提高存取速度,編譯器優化時有時會先把變量讀取到一個寄存器中;以後,再取變量值時,就直接從寄存器中取值;當變量值在本線程裏改變時,會同時把變量的新值copy到該寄存器中,以便保持一致。
當變量在因別的線程等而改變了值,該寄存器的值不會相應改變,從而造成應用程序讀取的值和實際的變量值不一致。
當該寄存器在因別的線程等而改變了值,原變量的值不會改變,從而造成應用程序讀取的值和實際的變量值不一致。
2>volatile應該解釋爲“直接存取原始內存地址”比較合適,“易變的”這種解釋簡直有點誤導人。

static const等等的用法,(能說出越多越好)
數據結構或者算法:
《離散數學》範圍內的一切問題皆由可能被深入問到(這個最坑爹,最重要,最體現功底,最能加分,特別是各類樹結構的實現和應用)
各類排序:大根堆的實現,快排(如何避免最糟糕的狀態?),bitmap的運用等等
hash, 任何一個技術面試官必問(例如爲什麼一般hashtable的桶數會取一個素數?如何有效避免hash結果值的碰撞)
網絡編程:
tcp與udp的區別(必問)
1.基於連接與無連接
2.對系統資源的要求(TCP較多,UDP少)
3.UDP程序結構較簡單
4.流模式與數據報模式
5.TCP保證數據正確性,UDP可能丟包,TCP保證數據順序,UDP不保證
TCP---傳輸控制協議,提供的是面向連接、可靠的字節流服務。當客戶和服務器彼此交換數據前,必須先在雙方之間建立一個TCP連接,之後才能傳輸數據。TCP提供超時重發,丟棄重複數據,檢驗數據,流量控制等功能,保證數據能從一端傳到另一端。
UDP---用戶數據報協議,是一個簡單的面向數據報的運輸層協議。UDP不提供可靠性,它只是把應用程序傳給IP層的數據報發送出去,但是並不能保證它們能到達目的地。由於UDP在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,故而傳輸速度很快

udp調用connect有什麼作用?
1:UDP中可以使用connect系統調用2:UDP中connect操作與TCP中connect操作有着本質區別.TCP中調用connect會引起三次握手,client與server建立連結.UDP中調用connect內核僅僅把對端ip&port記錄下來.3:UDP中可以多次調用connect,TCP只能調用一次connect.UDP多次調用connect有兩種用途:1,指定一個新的ip&port連結.2,斷開和之前的ip&port的連結.指定新連結,直接設置connect第二個參數即可.斷開連結,需要將connect第二個參數中的sin_family設置成 AF_UNSPEC即可. 4:UDP中使用connect可以提高效率.原因如下:普通的UDP發送兩個報文內核做了如下:#1:建立連結#2:發送報文#3:斷開連結#4:建立連結#5:發送報文#6:斷開連結采用connect方式的UDP發送兩個報文內核如下處理:#1:建立連結#2:發送報文#3:發送報文另外一點,每次發送報文內核都由可能要做路由查詢.5:採用connect的UDP發送接受報文可以調用send,write和recv,read操作.當然也可以調用sendto,recvfrom.調用sendto的時候第五個參數必須是NULL,第六個參數是0.調用recvfrom,recv,read系統調用只能獲取到先前connect的ip&port發送的報文.
UDP中使用connect的好處:1:會提升效率.前面已經描述了.2:高併發服務中會增加系統穩定性.原因:假設client A 通過非connect的UDP與server B,C通信.B,C提供相同服務.爲了負載均衡,我們讓A與B,C交替通信.A 與 B通信IPa:PORTa <----> IPb:PORTbA 與 C通信IPa:PORTa' <---->IPc:PORTc
假設PORTa 與 PORTa'相同了(在大併發情況下會發生這種情況),那麼就有可能出現A等待B的報文,卻收到了C的報文.導致收報錯誤.解決方法內就是採用connect的UDP通信方式.在A中創建兩個udp,然後分別connect到B,C.
tcp連接中時序圖,狀態圖,必須非常非常熟練


socket服務端的實現,select和epoll的區別(必問)
select的本質是採用32個整數的32位,即32*32= 1024來標識,fd值爲1-1024。當fd的值超過1024限制時,就必須修改FD_SETSIZE的大小。這個時候就可以標識32*max值範圍的fd。
對於單進程多線程,每個線程處理多個fd的情況,select是不適合的。
1.所有的線程均是從1-32*max進行掃描,每個線程處理的均是一段fd值,這樣做有點浪費
2.1024上限問題,一個處理多個用戶的進程,fd值遠遠大於1024
所以這個時候應該採用poll,
poll傳遞的是數組頭指針和該數組的長度,只要數組的長度不是很長,性能還是很不錯的,因爲poll一次在內核中申請4K(一個頁的大小來存放fd),儘量控制在4K以內
epoll還是poll的一種優化,返回後不需要對所有的fd進行遍歷,在內核中維持了fd的列表。select和poll是將這個內核列表維持在用戶態,然後傳遞到內核中。但是隻有在2.6的內核才支持。
epoll更適合於處理大量的fd ,且活躍fd不是很多的情況,畢竟fd較多還是一個串行的操作

epoll哪些觸發模式,有啥區別?(必須非常詳盡的解釋水平觸發和邊緣觸發的區別,以及邊緣觸發在編程中要做哪些更多的確認)
epoll可以同時支持水平觸發和邊緣觸發(Edge Triggered,只告訴進程哪些文件描述符剛剛變爲就緒狀態,它只說一遍,如果我們沒有采取行動,那麼它將不會再次告知,這種方式稱爲邊緣觸發),理論上邊緣觸發的性能要更高一些,但是代碼實現相當複雜。
epoll同樣只告知那些就緒的文件描述符,而且當我們調用epoll_wait()獲得就緒文件描述符時,返回的不是實際的描述符,而是一個代表就緒描述符數量的值,你只需要去epoll指定的一個數組中依次取得相應數量的文件描述符即可,這裏也使用了內存映射(mmap)技術,這樣便徹底省掉了這些文件描述符在系統調用時複製的開銷。
另一個本質的改進在於epoll採用基於事件的就緒通知方式。在select/poll中,進程只有在調用一定的方法後,內核纔對所有監視的文件描述符進行掃描,而epoll事先通過epoll_ctl()來註冊一個文件描述符,一旦基於某個文件描述符就緒時,內核會採用類似callback的回調機制,迅速激活這個文件描述符,當進程調用epoll_wait()時便得到通知。

大規模連接上來,併發模型怎麼設計
tcp結束連接怎麼握手,time_wait狀態是什麼,爲什麼會有time_wait狀態?哪一方會有time_wait狀態,如何避免time_wait狀態佔用資源(必須回答的詳細)
tcp頭多少字節?哪些字段?(必問)
頭20字節,選項12字節
什麼是滑動窗口(必問)
動窗口(Sliding window )是一種流量控制技術。滑動窗口協議是用來改善吞吐量的一種技術,即容許發送方在接收任何應答之前傳送附加的包。接收方告訴發送方在某一時刻能送多少包(稱窗口尺寸)。TCP中採用滑動窗口來進行傳輸控制,滑動窗口的大小意味着接收方還有多大的緩衝區可以用於接收數據。發送方可以通過滑動窗口的大小來確定應該發送多少字節的數據。當滑動窗口爲0時,發送方一般不能再發送數據報,但有兩種情況除外,一種情況是可以發送緊急數據,例如,允許用戶終止在遠端機上的運行進程。另一種情況是發送方可以發送一個1字節的數據報來通知接收方重新聲明它希望接收的下一字節及發送方的滑動窗口大小。滑動窗口協議的基本原理就是在任意時刻,發送方都維持了一個連續的允許發送的幀的序號,稱爲發送窗口;同時,接收方也維持了一個連續的允許接收的幀的序號,稱爲接收窗口。發送窗口和接收窗口的序號的上下界不一定要一樣,甚至大小也可以不同。不同的滑動窗口協議窗口大小一般不同。發送方窗口內的序列號代表了那些已經被髮送,但是還沒有被確認的幀,或者是那些可以被髮送的幀。
connect會阻塞,怎麼解決?(必考必問)
最通常的方法最有效的是加定時器;也可以採用非阻塞模式。
設置非阻塞,返回之後用select檢測狀態)
如果select返回可讀,結果只讀到0字節,什麼情況?
某個套接字集合中沒有準備好,可能會select內存用FD_CLR清該位爲0;
keepalive 是什麼東東?如何使用?
設置Keepalive參數,檢測已中斷的客戶連接
•     Determine how long to wait before probing the connection. On most platforms the default is 2 hours.
•     Determine how long to wait before retrying the probe.
•     Determine how many times to probe the connection.

列舉你所知道的tcp選項,並說明其作用。
1.窗口擴大因子TCP Window Scale Option (WSopt)
TCP窗口縮放選項是用來增加TCP接收窗口的大小而超過65536字節。
2.SACK選擇確認選項
最大報文段長度(M S S)表示T C P傳往另一端的最大塊數據的長度。當建立一個連接時,每一方都有用於通告它期望接收的 M S S選項(M S S選項只能出現在S Y N報文段中)。通過MSS,應用數據被分割成TCP認爲最適合發送的數據塊,由TCP傳遞給IP的信息單位稱爲報文段或段(segment)。
TCP通信時,如果發送序列中間某個數據包丟失,TCP會通過重傳最後確認的包開始的後續包,這樣原先已經正確傳輸的包也可能重複發送,急劇降低了TCP性能。爲改善這種情況,發展出SACK(Selective Acknowledgment, 選擇性確認)技術,使TCP只重新發送丟失的包,不用發送後續所有的包,而且提供相應機制使接收方能告訴發送方哪些數據丟失,哪些數據重發了,哪些數 據已經提前收到等。
3.MSS: Maxitum Segment Size 最大分段大小
socket什麼情況下可讀?
a. The number of bytes of data in the socket receive buffer is greater than or
     equal to the current size of the low-water mark for the socket receive buffer.
     A read operation on the socket will not block and will return a value greater than 0
b.  The read half of the connections is closed (i.e., A TCP connection that has received a FIN).
     A read operation on the socket will not block and will return 0 (i.e., EOF)
c. The socket is a listening socket and the number of completed connection is nonzero.
    An accept on the listening socket will normally not block, although we will describe a  
d. A socket error is pending. A read operation on the socket will not block and will return
    an error (-1) with errno set to the specific error condition
db:
mysql,會考sql語言,服務器數據庫大規模數據怎麼設計,db各種性能指標
最後:補充一個最最重要,最最坑爹,最最有難度的一個題目:一個每秒百萬級訪問量的互聯網服務器,每個訪問都有數據計算和I/O操作,如果讓你設計,你怎麼設計?

2015騰訊後臺開發面試經驗分享(武漢站) - 面試 問題 - IT面試 專業的IT面試社區 - IT面試基礎、IT面試經歷、公司職場點評、職位經驗分享

下午2:30,珞珈山國際大酒店。

第三次來到這裏了,前兩次的騰訊實習生面試都是一面就掛了。今天的運氣也不怎麼好,估計又掛在一面了。閒話少敘,面試題記錄如下:

1.自我介紹加介紹項目

答:blablabla....

2.core文件是什麼,有什麼用?

答:程序崩潰以後,會把最後的棧信息存在core文件裏,方便程序員瞭解程序崩潰前最後的棧信息。

追問:如果程序core了,但沒產生core問價,是何原因?

答:沒有打開core文件生成的開關。ulimit -c unlimit

追問:不用core文件,程序出了問題產生信號是否知道?

答:當時蒙了,現在回想起來,就是內核向進程發信號嘛。沒答出來。

3.共享內存,不使用同步方式,是否可以安全讀寫?

答:這一題答偏了,不知怎麼扯到fork上去了。這一題應該是不行,共享內存屬於臨界區,應該要同步,否則兩個進程同時操作一個內存區就出問題了。可以使用讀寫鎖來同步。

4.fork後,子進程保留了父進程的什麼?

答:子進程的內存區是父進程的副本,堆棧等都會繼承過來,還有打開的文件描述符等。其實還有很多,比如實際用戶ID,有效用戶ID,當前工作目錄,存儲映射等等。

5.共享內存除了文件映射還有什麼方式?

答:共享內存對象映射。

追問:二者有什麼區別?

答:不知道。

6.tcp怎麼實現流量控制?

答:對端告知窗口大小。本端傳遞的數據量小於窗口大小。(更好的說法是告訴對端本地的窗口的大小,對端傳遞的數據量必須小於該窗口)

追問:怎麼告知窗口大小?

答:在ACK的報文裏。

7.編程題(沒搞出來,誒~)

問:一個超長字符串表示的十進制數(大於2^32),轉化爲十六進制的字符串?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章