1. 程式人生 > >CVTE二面(電話面)

CVTE二面(電話面)

突然來個電話,本以為掛了的一面,居然進了二面,驚喜啊。。。雖然說仍然是個被虐的過程。雖然剛面完,但還是由於緊張,我都忘了問過些啥了,我儘量回憶下,順序可能不對。

0.自我介紹

1.還是先說專案,問一下有沒用過什麼技術點。

2.講下arpa協議(我沒聽懂到底什麼意思,是ARPA網還是ARP協議)

ARPA網中互連的執行使用者應用程式的主計算機稱為主機(Host)。主機之間通過介面報文處理機IMP(Interface Message Processor)的裝置轉接後互連。轉接方式稱為儲存轉發。儲存轉發即先儲存再轉發,類似於郵政信件或者快遞的傳送方式。當某主機上的使用者要訪問網路上另一臺主機時,主機先將資訊送至本地直連的IMP,然後根據適當的通訊線路轉至其他IMP,最後送至目標主機。

轉接機制:介面報文處理機IMP先將送來的資訊接收並儲存,當本地IMP和下一個IMP之間的通訊線路都空閒時,本地IMP將資訊傳給下一個IMP。

使用儲存轉發方式的優點:遠端通訊中,通訊線路是個比較昂貴的資源。儲存轉發技術即把需要傳送的資料緩衝儲存在裝置的資料緩衝區,當通道空閒時再選擇路徑轉發出去,極大地提高了通訊線路的有效利用率,節省了建立電路的延遲,也可以進行差錯控制、流量控制和資料安全保障等。

ARPA也是乙太網介面的一種封裝型別ARP(地址解析協議)型別,此欄位表示分配的ARP(地址解析協議)型別。預設情況下,乙太網使用ARPA關鍵字來指定IP介面的ARPA封裝。

/**********************************************************************/

ARP:

1.     原理:(ARP協議只使用於區域網中)

1>   在區域網中,網路中實際傳輸的是“幀”,幀裡面是有目標主機的MAC地址的。

2>   在乙太網中,一個主機要和另一個主機進行直接通訊,必須要知道目標主機的MAC地址。但這個目標MAC地址是如何獲得呢?它就是通過地址解析協議獲得的。所謂“地址解析”就是主機在傳送幀前將目標IP地址轉換成目標MAC地址的過程。

3>   ARP協議的基本功能就是通過目標裝置的IP地址,查詢目標裝置的MAC地址,以保證通訊的順利進行。

4>   點對點的連線是不需要ARP協議的

2.    工作過程:

1>   當主機A向本區域網上的某個主機B傳送IP資料報時,就先在自己的ARP緩衝表中檢視有無主機B的IP地址。

2>   如果有,就可以查出其對應的硬體地址,再將此硬體地址寫入MAC幀,然後通過乙太網將資料包傳送到目的主機中。

3>   如果查不到主機B的IP地址的表項。可能是主機B才入網,也可能是主機A剛剛加電。其高速緩衝表還是空的。在這中情況下,主機A就自動執行ARP。

(1)ARP程序在本區域網上廣播一個ARP請求分組。ARP請求分組的主要內容是表明:我的IP地址是192.168.0.2,我的硬體地址是00-00-C0-15-AD-18.我想知道IP地址為192.168.0.4的主機的硬體地址。

(2)在本區域網上的所有主機上執行的ARP進行都收到此ARP請求分組。

(3)主機B在ARP請求分組中見到自己的IP地址,就向主機A傳送ARP響應分組,並寫入自己的硬體地址。其餘的所有主機都不理睬這個ARP請求分組。ARP響應分組的主要內容是表明:“我的IP地址是192.168.0.4,我的硬體地址是08-00-2B-00-EE-AA”,請注意:雖然ARP請求分組是廣播發送的,但ARP響應分組是普通的單播,即從一個源地址傳送到一個目的地址。

(4)主機A收到主機B的ARP響應分組後,就在其ARP高速緩衝表中寫入主機B的IP地址到硬體地址的對映。

3.TCP/IP網路程式設計的步驟

伺服器端:1)建立套接字;2)繫結埠號bind;3)監聽連線listen;4)接受連線請求accept,並返回新的套接字;5)用新返回的套接字recv/send;6)關閉套接字。

客戶端:1)建立套接字create; 2)發起建立連線請求connect; 3)傳送/接收資料send/recv;4)關閉套接字。

4.TCP普通的方式能不能實現十萬條連線,理論上分析下為什麼。

單機最大tcp連線數

網路程式設計

在tcp應用中,server事先在某個固定埠監聽,client主動發起連線,經過三路握手後建立tcp連線。那麼對單機,其最大併發tcp連線數是多少?

如何標識一個TCP連線

在確定最大連線數之前,先來看看系統如何標識一個tcp連線。系統用一個4四元組來唯一標識一個TCP連線:{local ip, local port,remote ip,remote port}。

client最大tcp連線數

client每次發起tcp連線請求時,除非繫結埠,通常會讓系統選取一個空閒的本地埠(local port),該埠是獨佔的,不能和其他tcp連線共享。tcp埠的資料型別是unsigned short,因此本地埠個數最大隻有65536,埠0有特殊含義,不能使用,這樣可用埠最多隻有65535,所以在全部作為client端的情況下,最大tcp連線數為65535,這些連線可以連到不同的server ip。

server最大tcp連線數

server通常固定在某個本地埠上監聽,等待client的連線請求。不考慮地址重用(unix的SO_REUSEADDR選項)的情況下,即使server端有多個ip,本地監聽埠也是獨佔的,因此server端tcp連線4元組中只有remote ip(也就是client ip)和remote port(客戶端port)是可變的,因此最大tcp連線為客戶端ip數×客戶端port數,對IPV4,不考慮ip地址分類等因素,最大tcp連線數約為2的32次方(ip數)×2的16次方(port數),也就是server端單機最大tcp連線數約為2的48次方。

實際的tcp連線數

上面給出的是理論上的單機最大連線數,在實際環境中,受到機器資源、作業系統等的限制,特別是sever端,其最大併發tcp連線數遠不能達到理論上限。在unix/linux下限制連線數的主要因素是記憶體和允許的檔案描述符個數(每個tcp連線都要佔用一定記憶體,每個socket就是一個檔案描述符),另外1024以下的埠通常為保留埠。在預設2.6核心配置下,經過試驗,每個socket佔用記憶體在15~20k之間。

影響一個socket佔用記憶體的引數包括:

rmem_max

wmem_max

tcp_rmem

tcp_wmem

tcp_mem

grep skbuff /proc/slabinfo

對server端,通過增加記憶體、修改最大檔案描述符個數等引數,單機最大併發TCP連線數超過10萬 是沒問題的,國外 Urban Airship 公司在產品環境中已做到 50萬併發 。在實際應用中,對大規模網路應用,還需要考慮C10K 問題。

5.(我提到了select,epoll,就讓我……)講講select,epoll的原理

呼叫select時,會發生以下事情:

  1. 從使用者空間拷貝fd_set到核心空間;
  2. 註冊回撥函式__pollwait;
  3. 遍歷所有fd,對全部指定裝置做一次poll(這裡的poll是一個檔案操作,它有兩個引數,一個是檔案fd本身,一個是當裝置尚未就緒時呼叫的回撥函式__pollwait,這個函式把裝置自己特有的等待佇列傳給核心,讓核心把當前的程序掛載到其中);
  4. 當裝置就緒時,裝置就會喚醒在自己特有等待佇列中的【所有】節點,於是當前程序就獲取到了完成的訊號。poll檔案操作返回的是一組標準的掩碼,其中的各個位指示當前的不同的就緒狀態(全0為沒有任何事件觸發),根據mask可對fd_set賦值;
  5. 如果所有裝置返回的掩碼都沒有顯示任何的事件觸發,就去掉回撥函式的函式指標,進入有限時的睡眠狀態,再恢復和不斷做poll,再作有限時的睡眠,直到其中一個裝置有事件觸發為止。
  6. 只要有事件觸發,系統呼叫返回,將fd_set從核心空間拷貝到使用者空間,回到使用者態,使用者就可以對相關的fd作進一步的讀或者寫操作了。

呼叫epoll_create時,做了以下事情:

  1. 核心幫我們在epoll檔案系統裡建了個file結點;
  2. 在核心cache裡建了個紅黑樹用於儲存以後epoll_ctl傳來的socket;
  3. 建立一個list連結串列,用於儲存準備就緒的事件。

呼叫epoll_ctl時,做了以下事情:

  1. 把socket放到epoll檔案系統裡file物件對應的紅黑樹上;
  2. 給核心中斷處理程式註冊一個回撥函式,告訴核心,如果這個控制代碼的中斷到了,就把它放到準備就緒list連結串列裡。

呼叫epoll_wait時,做了以下事情:

觀察list連結串列裡有沒有資料。有資料就返回,沒有資料就sleep,等到timeout時間到後即使連結串列沒資料也返回。而且,通常情況下即使我們要監控百萬計的控制代碼,大多一次也只返回很少量的準備就緒控制代碼而已,所以,epoll_wait僅需要從核心態copy少量的控制代碼到使用者態而已。

6.自旋鎖

它是為實現保護共享資源而提出一種鎖機制。其實,自旋鎖與互斥鎖比較類似,它們都是為了解決對某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多隻能有一個保持者,也就說,在任何時刻最多隻能有一個執行單元獲得鎖。但是兩者在排程機制上略有不同。對於互斥鎖,如果資源已經被佔用,資源申請者只能進入睡眠狀態。但是自旋鎖不會引起呼叫者睡眠,如果自旋鎖已經被別的執行單元保持,呼叫者就一直迴圈在那裡看是否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是因此而得名。

7.程序間同步的方法,要很具體的講

見部落格。

8.過載的實現方式

函式過載。運算子過載(成員函式或者是友元的方式)。具體見部落格

9.引數列表裡有const能不能過載(這麼簡單的我居然搞忘了。。。)

可基於函式的引用形參是指向 const 物件還是指向非 const 物件,實現函式過載。將引用形參定義為 const 來過載函式是合法的,因為編譯器可以根據實參是否為 const 確定呼叫哪一個函式。

const 物件只能呼叫const 方法,非const 物件既能呼叫const 方法也能呼叫非const方法,優先呼叫非const方法。

如果過載的函式都是引用或指標,const 變數只能呼叫帶有const 引數的方法,非const 變數既能呼叫帶const 引數的方法,也能呼叫不帶cosnt 引數的方法,優先呼叫不帶const 引數的方法。

10.vector裡面能不能包含引用

《C++ primer》上說 vector 中不能存放引用的原因是:引用不支援一般意義上的賦值操作,而 vector中元素的兩個要求是:

1.元素必須能賦值

2.元素必須能複製

11.用過智慧指標麼,怎麼用智慧指標維護一個數組,比如 int A[10] = new int;怎麼用shared_ptr維護A。不懂這個問題在說什麼

12.一個程式的編譯連結的具體過程

1. 預處理

預處理相當於根據預處理指令組裝新的C/C++程式。經過預處理,會產生一個沒有巨集定義,沒有條件編譯指令,沒有特殊符號的輸出檔案,這個檔案的含義同原本的檔案無異,只是內容上有所不同。

讀取C/C++源程式,對其中的偽指令(以#開頭的指令)進行處理

①將所有的“#define”刪除,並且展開所有的巨集定義

②處理所有的條件編譯指令,如:“#if”、“#ifdef”、“#elif”、“#else”、“endif”等。這些偽指令的引入使得程式設計師可以通過定義不同的巨集來決定編譯程式對哪些程式碼進行處理。預編譯程式將根據有關的檔案,將那些不必要的程式碼過濾掉。

③處理“#include”預編譯指令,將被包含的檔案插入到該預編譯指令的位置。

(注意:這個過程可能是遞迴進行的,也就是說被包含的檔案可能還包含其他檔案)

刪除所有的註釋

新增行號和檔名標識。

以便於編譯時編譯器產生除錯用的行號資訊及用於編譯時產生的編譯錯誤或警告時能夠顯示行號

保留所有的#pragma編譯器指令

2. 編譯

將預處理完的檔案進行一系列詞法分析、語法分析、語義分析及優化後,產生相應的彙編程式碼檔案。

3. 彙編

將編譯完的彙編程式碼檔案翻譯成機器指令,並生成可重定位目標程式的.o檔案,該檔案為二進位制檔案,位元組編碼是機器指令。

彙編器是將彙編程式碼轉變成機器可以執行的指令,每一個彙編語句幾乎都對應一條機器指令。所以彙編器的彙編過程相對於編譯器來講比較簡單,它沒有複雜的語法,也沒有語義,也不需要做指令優化,只是根據彙編指令和機器指令的對照表一一翻譯即可。

4. 連結

通過連結器將一個個目標檔案(或許還會有庫檔案)連結在一起生成一個完整的可執行程式。

由彙編程式生成的目標檔案並不能立即就被執行,其中可能還有許多沒有解決的問題。

例如,某個原始檔中的函式可能引用了另一個原始檔中定義的某個符號(如變數或者函式呼叫等);在程式中可能呼叫了某個庫檔案中的函式,等等。所有的這些問題,都需要經連結程式的處理方能得以解決。

連結程式的主要工作就是將有關的目標檔案彼此相連線,也就是將在一個檔案中引用的符號同該符號在另外一個檔案中的定義連線起來,使得所有的這些目標檔案成為一個能夠被作業系統裝入執行的統一整體。

至此,大致經過這幾個步驟,一個完整的可執行程式產生了。

13.靜態成員變數是怎麼申明定義的,能不能在類的裡面申明定義。

靜態成員不屬於類的任何物件,所以並不是物件建立時被定義的,所以它不能由類的建構函式初始化,一般也不能在類內初始化。

關鍵字static只出現類的內部。

1、在類外定義且初始化

2、常量靜態成員可以在類內初始化

14.假如這次面試掛了你有什麼想法(我。。。我雖知道我這水平必掛,但這太直接了吧- -!)

15.怎麼學習的,看什麼書、網站

16.怎麼評價自己,優勢是什麼

17.最後有什麼想說的?(就是告別啊= .=!!)