來源:https://www.nowcoder.com/discuss/125248

秋招結束,春招再戰!(附面經)

樓主菜雞一隻,是真的菜,我是轉軟件的,所以學的很淺,面試根本經不起深挖,研一荒廢了半年,春節之後才意識到要開始找工作,然後就開始瘋狂的學習數據結構算法,計網,OS啥的,學的很水,前後投了20多家,最終就拿了4個小廠的offer,大廠真的一個都沒過,是真的應證了那句不經歷秋招就不知道自己有多菜,要是能有找工作的意識,估計不會是現在這個樣子了。因爲6月的時候拿了一個vivo提前批的sp,所以後面找工作基本全是找的互聯網公司,最後騙到了兩個互聯網的offer,應該是選擇貝殼吧。現在是到了回饋牛客的時候了,給下屆牛友分享下個人的菜雞經驗,總體應聘情況如下:

vivo 軟件崗sp,筆試面試都很簡單,沒有問太多基本知識,隨便聊了一下項目,但是面試體驗非常好,應該可以和貝殼並列No.1

OPPO 拿了vivo之後就參加了oppo的提前批,同樣也拿到了,不過是白菜價,後來去了OPPO總部和深圳那邊去參加了開放日(好像就提前批有),體驗非常棒,不得不說oppo是很捨得花錢的,不過就是月薪太低了,年終倒是挺高的,但是要工作的第三年才能拿到第一次的年終,我覺得時間太長了所以沒有考慮

貝殼 我是提前批參加的貝殼面試,通過了,當時讓我去北京現場面試,然後報銷800路費,但是覺得這個公司好扣啊,才報800(因爲我在武漢讀書,去北京來回車票至少1000塊啊,而且當時正在oppo開放日,他們全部報銷,所以心裏一下子就拒了),但是,但是,後來給我打電話的HR說可以可以標記一下,後來可以在武漢現場面試,然後我就答應了,等去貝殼面試的時候,才發現貝殼面試體驗是真的好,面試官沒有一點架子,而且會引導(即使我是個跨行的菜雞),最後過了三面,拿了貝殼的offer,也查了一下貝殼的背景和待遇,看着還不錯,所以基本就確定這家了

去哪兒網 今年貌似很缺人,感覺一面挺簡單,二面問的我也沒答上來,但是讓我過了,隨後就去hr面,然鵝太菜了hr說我技術評價不高給了勸退家,所以就沒有考慮了

阿里 阿里是直接一面掛了,當時好多東西沒有接觸,直接被問蒙了

網易遊戲 筆試a了2.5題,給了面試機會,現場面試先做代碼測試,寫的是一道圖的連通子集的題目,寫的不好,面試回答也不行,就掛了,網易遊戲很看重基礎知識

網易 簡歷就掛了

CVTE 投的計算機三維視覺算法崗,簡歷掛

百度 百度投的移動軟件,然而一點都不會,筆試隨便做了做,但是還是給了面試機會,hr打電話說讓我去面試說了時間地點,當時沒聽清楚,後來也沒有發短信,所以就鴿了

騰訊 面騰訊的時候已經很晚了,當時都不想面試了,太累了,而且騰訊還是測試開發崗,我都不怎麼懂,筆試做的賊差,也是讓我去面試,結果一面面試官搞我,感覺一副很瞧不起我的樣子,還讓我寫測試用例代碼,我不會,讓我回去了,奇怪的是居然讓我一面過了,讓我去二面,因爲一面體驗不好,就鴿了二面

小米 這也是一個神奇的公司,我7月內推的,結果9月才讓我筆試,我筆試也沒有參加,就說我筆試通過了讓我去面試,鴿了

大疆創新 筆試就掛了,看不懂刷人的套路

作業幫 當時和華爲筆試衝突了,做完了華爲之後做了1個小時的作業幫,發現題目還挺難,編程一道沒搞出來,筆試就這樣掛了

搜狗 這個公司也是牛叉啊,我投了C++開發和測試開發,讓我去面了兩次,第一次是去面試測試,結果全程測智商,醉了,做的太差,可以看下這篇面經:搜狗涼麪,第二次是面試C++,全程寫代碼,先寫了堆,push,top,pop函數,然後我說了思路,面試官說是對的,讓我寫,我憋了半天沒寫出來,實在是忘了咋寫了,後面又是讓我寫鏈表合併,動態規劃,沒有寫出來,就讓我涼了

face++ 現場筆試,感覺做的不錯,然鵝沒信

深信服 提前批筆試掛了,秋招筆試做的很差,讓我去面試,鴿了

華爲 筆試超簡單,算法都不考的,一面問了好多基礎知識,還有兩道智商題,一個是估計一個10平方的房間可以裝下多少乒乓球,另外一個是用兩個雞蛋測量臨界樓層,三個雞蛋怎麼測試?二面就是談人生了,現在還在池子裏,估計要被淹死

京東 一面挺簡單,但是還是掛了

新浪 最後一場面試,當時那天狀態特別差,導致面試完全沒準備,答得不好,但是講道理是不難的,一面掛

知乎 投了簡歷沒做測評,掛

招銀網絡 筆試簡單,面試鴿了(當時去了搜狗面試,後來後悔死了,圖安穩的真的可以考慮這個公司)

美團 一面感覺不難,常規題目,還是掛了

電信IT中心 去了宣講會感覺國企味兒太濃,面試就沒去

歡聚時代 筆試很容易,收到面試通知了,但是因爲12號面試太晚了,都快學校發三方了,所以不想去了,但是據說今年工資給的很高啊

搜狐 愛奇藝 這兩家筆試都挺簡單的,然鵝沒信了,肯定是掛了

以上就我投的公司了,也不算很多,怕投太多準備不過來,我同學都投了70家,嚇死人。太菜了已經面不動了,準備再搞一搞弄一弄春招了,看能不能撿個漏。

下面就是我整理的一些面試問題,可以參考一下

C++軟件工程師面試考點

C++軟件工程師面試考察主要有C++基礎(最好也懂Java)、數據結構及簡單算法、TCP、操作系統、網絡編程、Linux基本操作和Shell編程、數據庫,設計模式和智力題也會涉及少量。

C++基礎

參考資料:《Effective C++》、《C++ Prime》、《STL源碼剖析》

C和C++的區別?

  1. C是面向過程的語言,C++是面向對象的語言
  2. C++中new和delete是對內存分配的運算符,取代了C中的malloc和free
  3. C++中有引用的概念,C中沒有
  4. C++引入了類的概念,C中沒有
  5. C++有函數重載,C中不能
  6. C變量只能在函數的開頭處聲明和定義,而C++隨時定義隨時使用


C++和Java之間的區別?

  1. Java的應用在高層,C++在中間件和底層
  2. Java語言簡潔;取消了指針帶來更高的代碼質量;完全面向對象,獨特的運行機制是其具有天然的可移植性。
  3. Java在web應用上具有C++無可比擬的優勢
  4. 垃圾回收機制的區別。C++ 用析構函數回收垃圾,Java自動回收,寫C和C++程序時一定要注意內存的申請和釋放。
  5. Java用接口(Interface)技術取代C++程序中的多繼承性


什麼是面向對象?面向對象的幾大特性是什麼?

面向對象是一種基於對象的、基於類的的軟件開發思想。面向對象具有繼承、封裝、多態的特性。

模型具體怎麼實現的?

指針和引用的區別

  1. 指針保存的是指向對象的地址,引用相當於變量的別名
  2. 引用在定義的時候必須初始化,指針沒有這個要求
  3. 指針可以改變地址,引用必須從一而終
  4. 不存在空應引用,但是存在空指針NULL,相對而言引用更加安全
  5. 引用的創建不會調用類的拷貝構造函數


new/delete與malloc/free的區別

  1. new是運算符,malloc是C語言庫函數
  2. new可以重載,malloc不能重載
  3. new的變量是數據類型,malloc的是字節大小
  4. new可以調用構造函數,delete可以調用析構函數,malloc/free不能
  5. new返回的是指定對象的指針,而malloc返回的是void*,因此malloc的返回值一般都需要進行類型轉化
  6. malloc分配的內存不夠的時候可以使用realloc擴容,new沒有這樣的操作
  7. new內存分配失敗拋出bad_malloc,malloc內存分配失敗返回NULL值


volatile關鍵字

  1. 訪問寄存器要比訪問內存要塊,因此CPU會優先訪問該數據在寄存器中的存儲結果,但是內存中的數據可能已經發生了改變,而寄存器中還保留着原來的結果。爲了避免這種情況的發生將該變量聲明爲volatile,告訴CPU每次都從內存去讀取數據。
  2. 一個參數可以即是const又是volatile的嗎?可以,一個例子是隻讀狀態寄存器,是volatile是因爲它可能被意想不到的被改變,是const告訴程序不應該試圖去修改他


static關鍵字的作用

  1. 修飾全局變量
  2. 修飾局部變量
  3. 修飾全局函數
  4. 修飾局部函數
  5. 修飾類的成員變量、成員函數


static修飾全局函數有什麼作用?

限制他的作用域只能在本文件之內。

extern關鍵字作用

聲明一個外部變量。

const關鍵字的作用

  1. const修飾全局變量
  2. const修飾局部變量
  3. const修飾指針,const int *
  4. const修飾指針指向的對象, int * const
  5. const修飾引用做形參
  6. const修飾成員變量,必須在構造函數列表中初始化
  7. const修飾成員函數,說明該函數不應該修改非靜態成員,但是這並不是十分可靠的,指針所指的非成員對象值可能會被改變


define/const/inline的區別

本質:define只是字符串替換,const參與編譯運行,具體的:

  1. define不會做類型檢查,const擁有類型,會執行相應的類型檢查
  2. define僅僅是宏替換,不佔用內存,而const會佔用內存
  3. const內存效率更高,編譯器通常將const變量保存在符號表中,而不會分配存儲空間,這使得它成爲一個編譯期間的常量,沒有存儲和讀取的操作

本質:define只是字符串替換,inline由編譯器控制,具體的:

  1. 內聯函數在編譯時展開,而宏是由預處理器對宏進行展開
  2. 內聯函數會檢查參數類型,宏定義不檢查函數參數 ,所以內聯函數更安全。
  3. 宏不是函數,而inline函數是函數
  4. 宏在定義時要小心處理宏參數,(一般情況是把參數用括弧括起來)。


C++預定義宏

宏描述_LINE_這會在程序編譯時包含當前行號_FILE_這會在程序編譯時包含當前文件名_DATE_這會包含一個形式爲 month/day/year_TIME_這會包含一個形式爲 hour:minute:second 的字符串,它表示程序被編譯的時間。


這些宏的實例:

#include 
using namespace std;
int main ()
{
cout << "Value of __LINE__ : " << __LINE__ << endl;
cout << "Value of __FILE__ : " << __FILE__ << endl;
cout << "Value of __DATE__ : " << __DATE__ << endl;
cout << "Value of __TIME__ : " << __TIME__ << endl;
return 0;
}

當上面的代碼被編譯和執行時,它會產生下列結果:

Value of __LINE__ : 6
Value of __FILE__ : test.cpp
Value of __DATE__ : Feb 28 2011
Value of __TIME__ : 18:52:48

C++構造函數能拋異常嗎?析構呢?

不能。

C++/C內存分配方式,堆與棧的區別

構造函數爲什麼不能定義爲虛函數,析構函數爲什麼可以?

  1. 虛函數的執行依賴於虛函數表。而虛函數表需要在構造函數中進行初始化工作,即初始化vptr,讓他指向正確的虛函數表。而在構造對象期間,虛函數表還沒有被初始化,將無法進行。
  2. 在類的繼承中,如果有基類指針指向派生類,那麼用基類指針delete時,如果不定義成虛函數,派生類中派生的那部分無法析構。
  3. 構造函數不要調用虛函數。在基類構造的時候,虛函數是非虛,不會走到派生類中,既是採用的靜態綁定。顯然的是:當我們構造一個子類的對象時,先調用基類的構造函數,構造子類中基類部分,子類還沒有構造,還沒有初始化,如果在基類的構造中調用虛函數,如果可以的話就是調用一個還沒有被初始化的對象,那是很危險的,所以C++中是不可以在構造父類對象部分的時候調用子類的虛函數實現。但是不是說你不可以那麼寫程序,你這麼寫,編譯器也不會報錯。只是你如果這麼寫的話編譯器不會給你調用子類的實現,而是還是調用基類的實現。


有哪些內存泄漏?如何判斷內存泄漏?如何定位內存泄漏?

==內存泄漏類型:==

  1. 堆內存泄漏 (Heap leak)。對內存指的是程序運行中根據需要分配通過malloc,realloc new等從堆中分配的一塊內存,再是完成後必須通過調用對應的 free或者delete 刪掉。如果程序的設計的錯誤導致這部分內存沒有被釋放,那麼此後這塊內存將不會被使用,就會產生Heap Leak.
  2. 系統資源泄露(Resource Leak).主要指程序使用系統分配的資源比如 Bitmap,handle ,SOCKET等沒有使用相應的函數釋放掉,導致系統資源的浪費,嚴重可導致系統效能降低,系統運行不穩定。

==檢測內存泄漏:==

  1. 在windows平臺下通過CRT中的庫函數進行檢測;
  2. 在可能泄漏的調用前後生成塊的快照,比較前後的狀態,定位泄漏的位置
  3. Linux下通過工具valgrind檢測


全局變量和局部變量的區別

C++智能指針

C++動態內存

C++11新特性

純虛函數的作用和實現方式

STL源碼、vector、list、map、set

字節對齊的原則

  1. 從0位置開始存儲;
  2. 變量存儲的起始位置是該變量大小的整數倍;
  3. 結構體總的大小是其最大元素的整數倍,不足的後面要補齊;
  4. 結構體中包含結構體,從結構體中最大元素的整數倍開始存;
  5. 如果加入pragma pack(n) ,取n和變量自身大小較小的一個。


空結構體的sizeof()返回值

答案是1

靜態連接與動態鏈接的區別

1.靜態鏈接

所謂靜態鏈接就是在編譯鏈接時直接將需要的執行代碼拷貝到調用處,優點就是在程序發佈的時候就不需要依賴庫,也就是不再需要帶着庫一塊發佈,程序可以獨立執行,但是體積可能會相對大一些。

2.動態鏈接

所謂動態鏈接就是在編譯的時候不直接拷貝可執行代碼,而是通過記錄一系列符號和參數,在程序運行或加載時將這些信息傳遞給操作系統,操作系統負責將需要的動態庫加載到內存中,然後程序在運行到指定的代碼時,去共享執行內存中已經加載的動態庫可執行代碼,最終達到運行時連接的目的。優點是多個程序可以共享同一段代碼,而不需要在磁盤上存儲多個拷貝,缺點是由於是運行時加載,可能會影響程序的前期執行性能。

多態是什麼?舉一個多態的例子

多態性與虛函數表

靜態多態和動態多態

多態分爲靜態多態和動態多態。靜態多態是通過重載和模板技術實現,在編譯的時候確定。動態多態通過虛函數和繼承關係來實現,執行動態綁定,在運行的時候確定。

重寫、重載與隱藏的區別

重載的函數都是在類內的。只有參數類型或者參數個數不同,重載不關心返回值的類型。

覆蓋(重寫)派生類中重新定義的函數,其函數名,返回值類型,參數列表都跟基類函數相同,並且基類函數前加了virtual關鍵字。

隱藏是指派生類的函數屏蔽了與其同名的基類函數,注意只要同名函數,不管參數列表是否相同,基類函數都會被隱藏。有兩種情況:(1)參數列表不同,不管有無virtual關鍵字,都是隱藏;(2)參數列表相同,但是無virtual關鍵字,也是隱藏。

必須在構造函數初始化式裏進行初始化的數據成員有哪些

1) 常量成員,因爲常量只能初始化不能賦值,所以必須放在初始化列表裏面

2) 引用類型,引用必須在定義的時候初始化,並且不能重新賦值,所以也要寫在初始化列表裏面

3) 沒有默認構造函數的類類型,因爲使用初始化列表可以不必調用默認構造函數來初始化,而是直接調用拷貝構造函數初始化

C++四種類型轉換

static_cast, dynamic_cast, const_cast, reinterpret_cast

  1. const_cast用於將const變量轉爲非const
  2. static_cast用的最多,對於各種隱式轉換,非const轉const,void*轉指針等, static_cast能用於多態想上轉化,如果向下轉能成功但是不安全,結果未知;
  3. dynamic_cast用於動態類型轉換。只能用於含有虛函數的類,用於類層次間的向上和向下轉化。只能轉指針或引用。向下轉化時,如果是非法的對於指針返回NULL,對於引用拋異常。要深入瞭解內部轉換的原理。
  4. reinterpret_cast幾乎什麼都可以轉,比如將int轉指針,可能會出問題,儘量少用;
  5. 爲什麼不使用C的強制轉換?C的強制轉換表面上看起來功能強大什麼都能轉,但是轉化不夠明確,不能進行錯誤檢查,容易出錯。


如何讓一個類不能實例化?

將類定義爲抽象基類或者將構造函數聲明爲private。

如何讓main函數之前執行函數?

  1. C++中在main函數之前定義一個全局對象,調用構造函數。
  2. C語言中使用gcc的attribute關鍵字,聲明constructor和destructor。


C++如何創建一個類,使得他只能在堆或者棧上創建?

1.只能在堆上生成對象:將析構函數設置爲私有。

原因:C++是靜態綁定語言,編譯器管理棧上對象的生命週期,編譯器在爲類對象分配棧空間時,會先檢查類的析構函數的訪問性。若析構函數不可訪問,則不能在棧上創建對象。

2.只能在棧上生成對象:將new 和 delete 重載爲私有。

原因:在堆上生成對象,使用new關鍵詞操作,其過程分爲兩階段:第一階段,使用new在堆上尋找可用內存,分配給對象;第二階段,調用構造函數生成對象。將new操作設置爲私有,那麼第一階段就無法完成,就不能夠再堆上生成對象。

C++命名空間,命名空間的嵌套

可作爲附加信息來區分不同庫中相同名稱的函數、類、變量等。使用了命名空間即定義了上下文。

#include 
using namespace std;
// 第一個命名空間
namespace first_space{
void func(){
cout << "Inside first_space" << endl;
}
}
// 第二個命名空間
namespace second_space{
void func(){
cout << "Inside second_space" << endl;
}
}
int main ()
{
// 調用第一個命名空間中的函數
first_space::func();
// 調用第二個命名空間中的函數
second_space::func();
return 0;
}

C++多線程

explict關鍵字的作用

數據結構與算法

參考資料:《大話數據結構》、《數據結構浙大版》、《算法設計與分析》、《算法導論》、《劍指offer》、《LeetCode》、《組合數學》

鏈表

  • 輸出鏈表中倒數第k個節點
  • 找到鏈表環結點入口
  • 單鏈表的倒置

排序算法

手寫快速排序(快速排序的基準)

/*快速排序函數*/

//輸入:待排序的數組,排序其實位置>=0,排序終止位置<=length(a) - 1

void QuickSortHelper(ElemType a[],int low,int high)
{
if(low >= high)
return;
ElemType temp = a[low]; //存儲序列首位元素
int i = low + 1;
int j = high;
while(i != j)
{
while(i < j && a[j] > temp)
j--;
while(i < j && a[i] < temp)
i++;
//交換兩個元素
if(i < j)
{
swap(a,i,j);
}
}
a[low] = a[i];
a[i] = temp;
QuickSortHelper(a,low,i -1);
QuickSortHelper(a,i + 1,high);
}
/*快速排序*/
void QuickSort(ElemType a[], int n)
{
QuickSortHelper(a,0,n-1);
}
歸併排序
/*兩個有序子列的合併*/
void Merge(ElemType a[], ElemType temp[], int left_begin, int right_begin, int right_end)
{
int left_end = right_begin - 1;
int i = left_begin; //存放結果數組的初始位置
int num_element = right_end - left_begin + 1;
//進行合併
while (left_begin <= left_end && right_begin <= right_end)
{
if (a[left_begin] <= a[right_begin])
temp[i++] = a[left_begin++];
else
temp[i++] = a[right_begin++];
}
while (left_begin <= left_end)
temp[i++] = a[left_begin++];
while (right_begin <= right_end)
temp[i++] = a[right_begin++];
//改變a中對應段的值
for (int j = 0; j < num_element; j++)
{
a[right_end] = temp[right_end];
right_end--;
}
}
/*遞歸進行*/
void MSort(ElemType a[], ElemType temp[], int begin, int end)
{
int mid;
if (begin < end)
{
mid = (begin + end) / 2;
MSort(a, temp, begin, mid);
MSort(a, temp, mid + 1, end);
Merge(a, temp, begin, mid + 1, end);
}
}
/*歸併排序*/
void MergeSort(ElemType a[], int n)
{
ElemType *temp = (int *)malloc(sizeof(int) * n);
if (temp != NULL)
{
MSort(a, temp, 0, n - 1);
free(temp);
}
else
cout << "空間不足!" << endl;
}

堆排序

/*調整爲最大堆*/
void PercDown(ElemType a[], int p, int n){
// 將N個元素的數組中以a[p]爲根的子堆調整爲關於a[i]的最小堆
int parent, child;
int x;
x = a[p]; //取出根節點的值
for (parent = p; (parent * 2 + 1) < n; parent = child){
child = parent * 2 + 1;
if ((child != n - 1) && (a[child] < a[child + 1]))
child++;
if (x >= a[child])
break;
else
a[parent] = a[child];
}
a[parent] = x;
}
/*堆排序*/
void HeapSort(ElemType a[], int n)
{
for (int i = n / 2; i >= 0; i--)
PercDown(a, i, n); //建立一個最大堆
for (int i = n - 1; i > 0; i--)
{
Swap(a, 0, i); //交換最大最小元素,把最大元素給a[i]
PercDown(a, 0, i); //剩下的i個元素調整爲最大堆
}
}

其他算法

給定N張撲克牌和一個隨機函數,設計一個洗牌算法

void shuffle(int cards[],int n)
{
if(cards==NULL)
return ;
srand(time(0));
for(int i=0;i {
//保證每次第i位的值不會涉及到第i位以前
int index=i+rand()%(n-i);
int temp=cards[i];
cards[i]=cards[index];
cards[index]=temp;
}
}

哈希表

哈希處理衝突的解決方法

  1. 開放地址法
  2. 鏈表法

二叉樹

  • 二叉樹的非遞歸前序遍歷,中序遍歷,後續遍歷,層序遍歷
  • 二叉樹的高度
  • 二叉樹的鏡像
  • 二叉樹的前k大個節點(堆排序)
  • 紅黑樹和平衡二叉樹

高級數據結構

  • 紅黑樹
  • 前綴樹

算法

  • 找到數組中第一次出現1次的值
  • 揹包九講
  • 最大回文子串(動態規劃)
  • 最長公共子序列(動態規劃)
  • 最長重複子序列(find和rfind的應用)
  • 找零錢問題(動態規劃&貪心算法)
  • 排列組合問題(遞歸&回溯)

海量數據處理問題

網絡技術(TCP/IP)

  • OSI七層網絡模型
  • TCP三次握手過程,爲什麼需要三次?
  1. 首先Client向Server發送請求報文段,同時同步自己的SYN(x),Client進入SYN_SENT狀態。
  2. Server接收到Client的請求報文段,返回CLient自己的seq(y)及ack(x+1),Server進入SYN_REVD狀態。
  3. CLinet收到Server的SYN+ACK包,向服務器發送一個序列號seq(x+1),確認號爲ack(y+1),此包發送完畢,Client和Server進入ESTABLISHED(TCP連接成功)狀態,完成三次握手。

需要三次的原因:防止已失效的報文段出現在本連接中。

  • TCP四次揮手的過程
  1. 客戶端發送斷開TCP連接請求的報文,其中報文中包含seq序列號,是由發送端隨機生成的,並且還將報文中的FIN字段置爲1,表示需要斷開TCP連接。(FIN=1,seq=x,x由客戶端隨機生成)
  2. 服務端會回覆客戶端發送的TCP斷開請求報文,其包含seq序列號,是由回覆端隨機生成的,而且會產生ACK字段,ACK字段數值是在客戶端發過來的seq序列號基礎上加1進行回覆,以便客戶端收到信息時,知曉自己的TCP斷開請求已經得到驗證。(FIN=1,ACK=x+1,seq=y,y由服務端隨機生成)
  3. 服務端在回覆完客戶端的TCP斷開請求後,不會馬上進行TCP連接的斷開,服務端會先確保斷開前,所有傳輸到A的數據是否已經傳輸完畢,一旦確認傳輸數據完畢,就會將回復報文的FIN字段置1,並且產生隨機seq序列號。(FIN=1,ACK=x+1,seq=z,z由服務端隨機生成)
  4. 客戶端收到服務端的TCP斷開請求後,會回覆服務端的斷開請求,包含隨機生成的seq字段和ACK字段,ACK字段會在服務端的TCP斷開請求的seq基礎上加1,從而完成服務端請求的驗證回覆。(FIN=1,ACK=z+1,seq=h,h爲客戶端隨機生成)
  5. 至此TCP斷開的4次揮手過程完畢
  • 爲什麼TCP建立連接需要三次握手,而斷開連接需要四次揮手?

因爲當Server端收到Client端的SYN連接請求報文後,可以直接發送SYN+ACK報文。其中ACK報文是用來應答的,SYN報文是用來同步的。但是關閉連接時,當Server端收到FIN報文時,很可能並不會立即關閉SOCKET,所以只能先回復一個ACK報文,告訴Client端,”你發的FIN報文我收到了”。只有等到我Server端所有的報文都發送完了,我才能發送FIN報文,因此不能一起發送。故需要四步握手。

  • TIME_WAIT的意義,爲什麼等於2MSL?

MSL是最長報文段壽命,設置的目的是:

  • 保證A發送的最後一個ACK能夠到達B
  • 防止已失效的報文段出現在本連接中
  • ==TCP頭部校驗的原理,安全嗎,可以仿造嗎==

TCP校驗和是一個端到端的校驗和,由發送端計算,然後由接收端驗證。其目的是爲了發現TCP首部和數據在發送端到接收端之間發生的任何改動。如果接收方檢測到校驗和有差錯,則TCP段會被直接丟棄。

可以仿造。

  • TCP、UDP的區別?服務器和客戶端建立的過程?

TCP---傳輸控制協議,提供的是面向連接、可靠的字節流服務。當客戶和服務器彼此交換數據前,必須先在雙方之間建立一個TCP連接,之後才能傳輸數據。TCP提供超時重發,丟棄重複數據,檢驗數據,流量控制等功能,保證數據能順序地從一端傳到另一端。

UDP---用戶數據報協議,是一個簡單的面向數據報的運輸層協議。UDP不提供可靠性,它只是把應用程序傳給IP層的數據報發送出去,但是並不能保證它們能到達目的地。由於UDP在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,不保證數據按順序傳遞,故而傳輸速度很快。

UDP編程的服務器端一般步驟

  1. 創建一個socket,用函數socket();
  2. 設置socket屬性,用函數setsockopt();* 可選
  3. 綁定IP地址、端口等信息到socket上,用函數bind();
  4. 循環接收數據,用函數recvfrom();
  5. 關閉網絡連接;

UDP編程的客戶端一般步驟是

  1. 創建一個socket,用函數socket();
  2. 設置socket屬性,用函數setsockopt();* 可選
  3. 綁定IP地址、端口等信息到socket上,用函數bind();* 可選
  4. 設置對方的IP地址和端口等屬性;
  5. 發送數據,用函數sendto();
  6. 關閉網絡連接;


TCP編程的服務器端一般步驟是

  1. 創建一個socket,用函數socket();
  2. 設置socket屬性,用函數setsockopt(); * 可選
  3. 綁定IP地址、端口等信息到socket上,用函數bind();
  4. 開啓監聽,用函數listen();
  5. 接收客戶端上來的連接,用函數accept();
  6. 收發數據,用函數send()和recv(),或者read()和write();
  7. 關閉網絡連接;
  8. 關閉監聽;


TCP編程的客戶端一般步驟是

  1. 創建一個socket,用函數socket();
  2. 設置socket屬性,用函數setsockopt();* 可選
  3. 綁定IP地址、端口等信息到socket上,用函數bind();* 可選
  4. 設置要連接的對方的IP地址和端口等屬性;
  5. 連接服務器,用函數connect();
  6. 收發數據,用函數send()和recv(),或者read()和write();
  7. 關閉網絡連接;
  • socket中的close是一次就關閉的嗎?半關閉狀態是怎麼產生的?

不是,當A發送給B控制FIN的時候,A到B這個方向的連接就關閉了,這個時候處於半關閉的狀態,但是B到A這個方向的連接並沒有關閉,因爲B要等到將數據全部發送完畢之後纔會發送FIN給A。

  • TCP擁塞控制

重點掌握慢開始、擁塞避免、快重傳、快恢復。

  • TCP流量控制,採用滑動窗口會用什麼問題?

流量控制是爲了讓發送方的發送速率不要太快,要讓接收方來得及接收。

Nagle算法:①當發送方首都哦啊哦對第一個數據字符的確認後,再把發送緩存中的所有數據組裝成一個報文段發送出去,同時繼續對隨後到到達的數據進行緩存。②當到達的數據已達到發送窗口大小的一半或已達到報文段的長度的時候就立即發送一個報文段。

糊塗窗口綜合徵:就是由於發送端和接收端上的處理不一致,導致網絡上產生很多的小包,結果報文段包含了一個大大的頭部,攜帶數據很少。數據傳輸效率低。處理方法是等待窗口大小滿足一定的條件之後(能夠接收一個最大報文,或者緩衝區的一半),再來發送窗口通告,這樣就不會產生小報文。

滑動窗口機制爲端到端設備間的數據傳輸提供了可靠的流量控制機制。然而,它只能在源端設備和目的端設備起作用,當網絡中間設備(例如路由器等)發生擁塞時,滑動窗口機制將不起作用。

  • 擁塞控制和流量控制的區別?
  1. 擁塞控制就是防止過多的數據注入到網絡中,這樣可以使網絡中的路由器或鏈路不會過載
  2. 流量控制往往是點對點通信量的控制,是一個端到端的問題,流量控制要做的是抑制發送端發送數據的速率,以便接收端來得及接收。
  • TCP怎麼保證可靠性?
  1. 應用數據被分割成TCP認爲最適合發送的數據塊
  2. 超時重傳:當TCP發出一個段後,它啓動一個定時器,等待目的端確認收到這個報文段。如果不能及時收到一個確認,將重發這個報文段
  3. TCP給發送的每一個包進行編號,接收方對數據包進行排序,把有序數據傳送給應用層
  4. 校驗和:TCP將保持它首部和數據的檢驗和。這是一個端到端的檢驗和,目的是檢測數據在傳輸過程中的任何變化。如果收到段的檢驗和有差錯,TCP將丟棄這個報文段和不確認收到此報文段
  5. TCP的接收端會丟棄重複的數據
  6. 流量控制:讓發送方的發送速率不要太快,要讓接收方來得及接收
  7. 擁塞控制:當網絡擁塞時,減少數據的發送
  • TCP滑動窗口協議
  1. “窗口”對應的是一段可以被髮送者發送的字節序列,其連續的範圍稱之爲“窗口”
  2. “滑動”則是指這段“允許發送的範圍”是可以隨着發送的過程而變化的,方式就是按順序“滑動”
  • http協議與TCP協議的聯繫

TPC協議是傳輸層協議,主要解決數據如何在網絡中傳輸,而HTTP是應用層協議,主要解決如何包裝數據。

Http協議是建立在TCP協議基礎之上的,當瀏覽器需要從服務器獲取網頁數據的時候,會發出一次Http請求。Http會通過TCP建立起一個到服務器的連接通道,當本次請求需要的數據完畢後,Http會立即將TCP連接斷開,這個過程是很短的。所以Http連接是一種短連接,是一種無狀態的連接。

  • http/1.0和http/1.1的區別?
  1. http1.1提供永久性連接,即1.0使用非持久連接
  2. http1.1增加host頭
  3. http1.1還提供了身份認證,狀態管理和cache緩存機制等相關的請求頭和響應頭。
  • http請求方法有哪些?get和post的區別

1.OPTIONS

返回服務器針對特定資源所支持的HTTP請求方法,也可以利用向web服務器發送‘*’的請求來測試服務器的功能性

2.HEAD

向服務器索與GET請求相一致的響應,只不過響應體將不會被返回。這一方法可以再不必傳輸整個響應內容的情況下,就可以獲取包含在響應小消息頭中的元信息。

3.GET

向特定的資源發出請求。注意:GET方法不應當被用於產生“副作用”的操作中,例如在Web Application中,其中一個原因是GET可能會被網絡蜘蛛等隨意訪問。Loadrunner中對應get請求函數:web_link和web_url

4.POST

向指定資源提交數據進行處理請求(例如提交表單或者上傳文件)。數據被包含在請求體中。POST請求可能會導致新的資源的建立和/或已有資源的修改。 Loadrunner中對應POST請求函數:web_submit_data,web_submit_form

5.PUT

向指定資源位置上傳其最新內容

6.DELETE

請求服務器刪除Request-URL所標識的資源

7.TRACE

回顯服務器收到的請求,主要用於測試或診斷

8.CONNECT

HTTP/1.1協議中預留給能夠將連接改爲管道方式的代理服務器。

(1)根據HTTP規範,GET用於信息獲取,而且應該是安全的和冪等的

(2)根據HTTP規範,POST表示可能修改變服務器上的資源的請求

  • http狀態碼


  • http和https的區別?由http升級到https需要哪些操作?

HTTP 指的是超文本傳輸協議,https 指的是超文本傳輸安全協議。HTTPS 就是將 HTTP 中的傳輸內容進行了加密,然後通過可靠的連接,傳輸到對方的機器上。加密的協議是 TLS,其前身是 SSL。

  • https具體怎麼實現?,怎麼確保安全性?


  • http中瀏覽器一個URL的流程,這個過程中瀏覽器做些什麼,URL包括哪三個部分?
  1. 瀏覽器向DNS服務器查找輸入URL對應的IP地址。
  2. DNS服務器返回網站的IP地址。
  3. 瀏覽器根據IP地址與目標web服務器在80端口上建立TCP連接
  4. 瀏覽器獲取請求頁面的html代碼。
  5. 瀏覽器在顯示窗口內渲染HTML。
  6. 窗口關閉時,瀏覽器終止與服務器的連接。
  7. URL包括:①協議(或稱爲服務方式);②存有該資源的主機IP地址(有時也包括端口號);③主機資源的具體地址,如目錄和文件名等。
  • http四個會話過程?
  1. 建立tcp連接
  2. 發出請求文檔
  3. 發出響應文檔
  4. 釋放tcp連接
  • 網頁解析的過程
  • 一個機器能使用的端口號上限是多少?爲什麼?可以改變嗎?如果想要用的端口超過這個限制怎麼辦?
  • 對稱加密和非對稱加密

對稱加密(也叫私鑰加密)指加密和解密使用相同密鑰的加密算法。有時又叫傳統密碼算法,就是加密密鑰能夠從解密密鑰中推算出來,同時解密密鑰也可以從加密密鑰中推算出來。

非對稱加密算法需要兩個密鑰:公開密鑰(publickey)和私有密鑰(privatekey)。公開密鑰與私有密鑰是一對,如果用公開密鑰對數據進行加密,只有用對應的私有密鑰才能解密;如果用私有密鑰對數據進行加密,那麼只有用對應的公開密鑰才能解密。因爲加密和解密使用的是兩個不同的密鑰,所以這種算法叫作非對稱加密算法。

  • 數字證書的瞭解(高頻)
  • 客戶端爲什麼信任第三方證書?
  • RSA加密算法,MD5原理
  • 單條記錄高併發訪問的優化
  • 介紹一下ping的過程,分別用到了那些協議?

ping用來測試兩臺主機之間的連通性。ICMP協議

  • TCP/IP分片粘包過程


正常情況:如果Socket Client 發送的數據包,在Socket Server端也是一個一個完整接收的,那個就不會出現粘包和分包情況,數據正常讀取。

粘包情況:Socket Client發送的數據包,在客戶端發送和服務器接收的情況下都有可能發送,因爲客戶端發送的數據都是發送的一個緩衝buffer,然後由緩衝buffer最後刷到數據鏈路層的,那麼就有可能把數據包2的一部分數據結合數據包1的全部被一起發送出去了,這樣在服務器端就有可能出現這樣的情況,導致讀取的數據包包含了數據包2的一部分數據,這就產生粘包,當然也有可能把數據包1和數據包2全部讀取出來。

分包情況:意思就是把數據包2或者數據包1都有可能被分開一部分發送出去,接着發另外的部分,在服務器端有可能一次讀取操作只讀到一個完整數據包的一部分。

在數據包發送的情況下,有可能後面的數據包分開成2個或者多個,但是最前面的部分包,黏住在前面的一個完整或者部分包的後面,也就是粘包和分包同時產生了。

  • 有沒有抓過TCP包,描述一下
  • 一個IP配置多個域名,靠什麼識別?

主機頭

  • 路由器的工作原理和作用,交換機的工作原理和作用
  • 對路由協議的瞭解與介紹。
  • 路由協議使用的算法
  • 服務器攻擊(DDos攻擊)

操作系統

  • 什麼是臨界區?進程進入臨界區的調度原則是?

臨界區是一段對共享資源的保護代碼,該保護代碼在任意時刻只允許一個線程對共享資源訪問。

進程進入臨界區的調度原則是:

①如果有若干進程要求進入空閒的臨界區,一次僅允許一個進程進入。②任何時候,處於臨界區內的進程不可多於一個。如已有進程進入自己的臨界區,則其它所有試圖進入臨界區的進程必須等待。③進入臨界區的進程要在有限時間內退出,以便其它進程能及時進入自己的臨界區。④如果進程不能進入自己的臨界區,則應讓出CPU,避免進程出現“忙等”現象。

  • 互斥對象、臨界區和事件的區別?

互斥是一種用途非常廣泛的內核對象。能夠保證多個線程對同一共享資源的互斥訪問。

事件對象也是屬於內核對象,它的主要成員包括:1.使用計數 2.指明該事件是一個自動重置事件還是一個人工重置事件的布爾值3.指明該事件處於已通知狀態還是未通知狀態的布爾值。

互斥對象、事件對象與臨界區的比較:

  • 互斥對象、事件對象都是屬於內核對象,利用內核對象進行線程同步,速度較慢,但可以在多個進程中的多個線程間可以進行同步。


  • 臨界區屬於在用戶模式下,同步速度較快,但是很容易進入死鎖狀態,因爲在等待進入臨界區時無法設定超時值。
  • 進程和線程的區別?進程和程序的區別?
  • 進程是資源(CPU、內存等)分配的基本單位,它是程序執行時的一個實例。程序運行時系統就會創建一個進程,併爲它分配資源,然後把該進程放入進程就緒隊列,進程調度器選中它的時候就會爲它分配CPU時間,程序開始真正運行。
  • 線程是程序執行時的最小單位,它是進程的一個執行流,是CPU調度和分派的基本單位,一個進程可以由很多個線程組成,線程間共享進程的所有資源,每個線程有自己的堆棧和局部變量。線程由CPU獨立調度執行,在多CPU環境下就允許多個線程同時運行。同樣多線程也可以實現併發操作,每個請求分配一個線程來處理。


進程和程序的區別

  • 進程是動態的,而程序是靜態的。
  • 進程有一定的生命期,而程序是指令的集合,本身無“運動”的含義。沒有建立進程的程序不能作爲1個獨立單位得到操作系統的認可。
  • 1個程序可以對應多個進程,但1個進程只能對應1個程序。進程和程序的關係猶如演出和劇本的關係。
  • 一個進程可以創建多少個線程?和什麼有關?
  • 一個進程可以創建的線程數由可用虛擬空間和線程的棧的大小共同決定


  • 殭屍進程?
  • 什麼是死鎖?死鎖產生的原因?死鎖四個必要條件?死鎖的解除、死鎖控制?
  • 死鎖是指多個進程因競爭資源而造成的一種僵局(互相等待),若無外力作用,這些進程都將無法向前推進。


死鎖產生的原因

  • 系統資源的競爭

系統資源的競爭導致系統資源不足,以及資源分配不當,導致死鎖。

  • 進程運行推進順序不合適

進程在運行過程中,請求和釋放資源的順序不當,會導致死鎖。

死鎖的四個條件

互斥條件:一個資源每次只能被一個進程使用,即在一段時間內某 資源僅爲一個進程所佔有。此時若有其他進程請求該資源,則請求進程只能等待。

請求與保持條件:進程已經保持了至少一個資源,但又提出了新的資源請求,而該資源 已被其他進程佔有,此時請求進程被阻塞,但對自己已獲得的資源保持不放。

不可剝奪條件:進程所獲得的資源在未使用完畢之前,不能被其他進程強行奪走,即只能 由獲得該資源的進程自己來釋放(只能是主動釋放)。

循環等待條件: 若干進程間形成首尾相接循環等待資源的關係

這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。

死鎖的避免與預防

死鎖避免的基本思想

系統對進程發出每一個系統能夠滿足的資源申請進行動態檢查,並根據檢查結果決定是否分配資源,如果分配後系統可能發生死鎖,則不予分配,否則予以分配。這是一種保證系統不進入死鎖狀態的動態策略。

理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大可能地避免、預防和解除死鎖。所以,在系統設計、進程調度等方面注意如何讓這四個必要條件不成立,如何確定資源的合理分配算法,避免進程永久佔據系統資源。此外,也要防止進程在處於等待狀態的情況下佔用資源。因此,對資源的分配要給予合理的規劃。

死鎖避免和死鎖預防的區別

死鎖預防是設法至少破壞產生死鎖的四個必要條件之一,嚴格的防止死鎖的出現,而死鎖避免則不那麼嚴格的限制產生死鎖的必要條件的存在,因爲即使死鎖的必要條件存在,也不一定發生死鎖。死鎖避免是在系統運行過程中注意避免死鎖的最終發生。

死鎖的解除

一旦檢測出死鎖,就應立即釆取相應的措施,以解除死鎖。死鎖解除的主要兩種方法:

1.搶佔資源。從一個或多個進程中搶佔足夠數量的資源,分配給死鎖進程,以解除死鎖狀態。

2.終止(或撤銷)進程。終止(或撤銷)系統中的一個或多個死鎖進程,直至打破循環環路,使系統從死鎖狀態解脫出來。

Windows內存管理方式

分頁存儲

用戶程序的邏輯地址空間被劃分成若干固定大小的區域,稱爲“頁”或者“頁面”,相應地,內存物理空間也分成相對應的若干個物理塊,頁和塊的大小相等。提高了內存的利用率。

分段存儲

將用戶程序地址空間分成若干個大小不等的段,每段可以定義一組相對完整的邏輯信息。提高程序的邏輯性。

段頁式存儲

兩者結合。作業的地址空間首先被分成若干個邏輯分段,每段都有自己的段號,然後再將每段分成若干個大小相等的頁。

一個程序從開始運行到結束的完整過程(四個過程)

預處理,編譯,彙編,鏈接。

源代碼.c 文件先經過預處理器,生成一箇中間文件.i 文件,這個階段有兩個作用,一是把include的頭文件內容進行替換,二是處理宏定義。

.i 文件經過編譯生成彙編.s 文件

.s 的彙編文件經過彙編器生成.obj 的目標文件

.obj 經過鏈接器和 lib(靜態鏈接庫) dll(動態鏈接庫)文件生成 exe 可執行程序

頭文件在編譯過程中的作用?(網易遊戲)

頭文件並不參加鏈接和編譯。編譯器第一步要做的就是簡單的把頭文件在包含它的源文件中展開。不知你是否能理解這句話。也就是頭文件裏面有什麼內容,通通把它移到包含這個頭文件的源文件裏。(我覺得這是個很重要的概念,可以幫助我們簡化理解編譯鏈接的過程,包括理解頭文件中定義靜態變量或靜態函數是怎麼回事)。編譯器經過這一步轉換後剩下什麼呢?就是一堆cpp文件了。而頭文件已經不再是編譯器需要關心的東西了。編譯器接下來就要處理這一堆cpp文件了。

所以第一個階段是預處理階段,在正式的編譯階段之前進行。預處理階段將根據已放置在文件中的預處理指令來修改源文件的內容。如#include指令就是一個預處理指令,它把頭文件的內容添加到.cpp文件中。 第二個階段編譯、優化階段。

爲何不能在頭文件中定義?

防止多重定義。

進程間通信的方法?

管道pipe:管道是一種半雙工的通信方式,數據只能單向流動,而且只能在具有親緣關係的進程間使用。進程的親緣關係通常是指父子進程關係。

命名管道FIFO:有名管道也是半雙工的通信方式,但是它允許無親緣關係進程間的通信。

消息隊列MessageQueue:消息隊列是由消息的鏈表,存放在內核中並由消息隊列標識符標識。消息隊列克服了信號傳遞信息少、管道只能承載無格式字節流以及緩衝區大小受限等缺點。

共享存儲SharedMemory:共享內存就是映射一段能被其他進程所訪問的內存,這段共享內存由一個進程創建,但多個進程都可以訪問。共享內存是最快的 IPC 方式,它是針對其他進程間通信方式運行效率低而專門設計的。它往往與其他通信機制,如信號兩,配合使用,來實現進程間的同步和通信。

信號量Semaphore:信號量是一個計數器,可以用來控制多個進程對共享資源的訪問。它常作爲一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作爲進程間以及同一進程內不同線程之間的同步手段。

套接字Socket:套解口也是一種進程間通信機制,與其他通信機制不同的是,它可用於不同及其間的進程通信。

信號 ( sinal ) : 信號是一種比較複雜的通信方式,用於通知接收進程某個事件已經發生。

線程同步方法?

鎖機制

互斥鎖:提供了以排它方式阻止數據結構被併發修改的方法。

讀寫鎖:允許多個線程同時讀共享數據,而對寫操作互斥。

條件變量:可以以原子的方式阻塞進程,直到某個特定條件爲真爲止。對條件測試是在互斥鎖的保護下進行的。條件變量始終與互斥鎖一起使用。

信號量機制:包括無名線程信號量與有名線程信號量

信號機制:類似於進程間的信號處理。

線程間通信的主要目的是用於線程同步,所以線程沒有象進程通信中用於數據交換的通信機制。

線程創建的方式有幾種?

進程調度算法?

先來先去服務

短作業(進程)優先調度算法SJ(P)F

輪轉法

多級反饋隊列算法

頁面置換方法

最優頁面置換算法

最近未使用頁面置換算法(NRU)

先進先出頁面置換算法(FIFO)及其改進

時鐘頁面置換算法(clock)

最近最少使用頁面置換算法(LRU)

工作集算法

布隆過濾器的優點與缺點

布隆過濾器處理大規模問題時的持久化,包括內存大小首先、磁盤換入換出問題

文件讀寫使用的系統調用

線程池的瞭解、優點、調度處理方式和保護任務隊列的方式

於是爲了避免一個程序需要大量創建線程時的不必要浪費,也就是最好的去避免線程創建與線程銷燬的時間浪費,此時線程池就出現了。線程池的實現就是在初始的時候創建一些線程(業界通常認爲創建CPU核心數的兩倍爲最佳,也有說是兩倍+1),創建的線程爲掛起狀態(就緒),當我們有任務要處理的時候,我們就激活一個就緒的線程去完成任務,完成任務後,線程又變爲就緒態進行繼續等待任務的到來。這樣過程使得每個線程一次創建,多次使用,如果你的程序並沒有多次任務處理,使得線程池中的線程長時間處於就緒態,此時就建議你直接使用一個線程就好,不必使用線程池。

線程池怎麼創建?

怎麼回收線程

多線程同步(項目中可能會問)

mencache

異常和中斷的區別

如何保證線程安全?

Linux

Linux的I/O模型介紹以及同步異步阻塞非阻塞的區別?

阻塞IO

非阻塞IO

IO複用

信號驅動IO

異步IO

Linux進程管理

Linux內核的進程調度

fork返回值是什麼?

什麼是虛擬內存?

文件系統的理解(EXT4,XFS,BTRFS)

EXT4:使用廣泛

XFS:XFS 文件系統是擴展文件系統的一個擴展,XFS 文件系統有一些缺陷,例如它不能壓縮,刪除大量文件時性能低下。

btrfs:有很多好用的功能,例如寫複製、擴展校驗、快照、清洗、自修複數據、冗餘刪除以及其它保證數據完整性的功能。

Linux的內存管理?

Linux基本命令?

命令作用

pwd顯示當前目錄

rm刪除

touch生成文件

cat讀取指定文件的內容並打印到終端輸出

mkdir新建目錄make directory

file查看文件類型

whereis,which,find 和 locate查找

chown改變文件所有者

df查看磁盤容量

wc計數工具

tr刪除一段文本信息中的某些文字。或者將其進行轉換

join連接兩個文件

paste它是在不對比數據的情況下,簡單地將多個文件合併一起,以Tab隔開

grep、awk、sed掌握程度?

grep命令用於打印輸出文本中匹配的模式串,它使用正則表達式作爲模式匹配的條件。

sed用於過濾和轉換文本的流編輯器。

AWK是一種用於處理文本的編程語言工具。

Linux是如何避免內存碎片的

夥伴算法,用於管理物理內存,避免內存碎片;

高速緩存Slab層用於管理內核分配內存,避免碎片。

文件權限的查看與修改?

文件權限查看ls -l,查看文件所有者,所屬組,其他的文件權限,rwx爲777

修改使用chmod命令

Linux如何打開一個文件?如何處理一個正在動態增長的文件?

IO複用的三種方法,poll、epoll和select的特點和區別

select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因爲他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而異步I/O則無需自己負責進行讀寫,異步I/O的實現會負責把數據從內核拷貝到用戶空間。

select:是最初解決IO阻塞問題的方法。用結構體fd_set來告訴內核監聽多個文件描述符,該結構體被稱爲描述符集。由數組來維持哪些描述符被置位了。對結構體的操作封裝在三個宏定義中。通過輪尋來查找是否有描述符要被處理,如果沒有返回。

存在的問題:

內置數組的形式使得select的最大文件數受限與FD_SIZE;

每次調用select前都要重新初始化描述符集,將fd從用戶態拷貝到內核態,每次調用select後,都需要將fd從內核態拷貝到用戶態;

輪尋排查當文件描述符個數很多時,效率很低;

poll:通過一個可變長度的數組解決了select文件描述符受限的問題。數組中元素是結構體,該結構體保存描述符的信息,每增加一個文件描述符就向數組中加入一個結構體,結構體只需要拷貝一次到內核態。poll解決了select重複初始化的問題。輪尋排查的問題未解決。

epoll:輪尋排查所有文件描述符的效率不高,使服務器併發能力受限。因此,epoll採用只返回狀態發生變化的文件描述符,便解決了輪尋的瓶頸。

爲什麼使用IO多路複用,最主要的原因是什麼?

epoll有兩種觸發模式?這兩種觸發模式有什麼區別?編程的時候有什麼區別?

上一題中編程的時候有什麼區別,是在邊緣觸發的時候要把套接字中的數據讀乾淨,那麼當有多個套接字時,在讀的套接字一直不停的有數據到達,如何保證其他套接字不被餓死。

GDB調試

Linux進程和線程如何創建、退出?進程退出的時候,自己沒有釋放的資源(如內存沒有free)會怎樣?

數據庫

存儲過程

我們常用的關係型數據庫是MySQL,操作數據庫的語言一般爲SQL語句,SQL在執行的時候需要要先編譯,然後執行,而存儲過程(Stored Procedure)是一組爲了完成某種特定功能的SQL語句集,經編譯後存儲在數據庫中,用戶通過指定存儲過程的名字並給定參數(如果該存儲過程帶有參數)來調用執行它。

一個存儲過程是一個可編程的函數,它在數據庫中創建並保存。它可以有SQL語句和一些特殊的控制結構組成。當希望在不同的應用程序或平臺上執行相同的函數,或者封裝特定功能時,存儲過程是非常有用的。數據庫中的存儲過程可以看做是對面向對象方法的模擬,它允許控制數據的訪問方式。

==存儲過程的優點:==

存儲過程增強了SQL語言的功能和靈活性:存儲過程可以用流控制語句編寫,有很強的靈活性,可以完成複雜的判斷和較複雜的運算。

存儲過程允許標準組件式編程:存儲過程被創建後,可以在程序中被多次調用,而不必重新編寫該存儲過程的SQL語句。而且可以隨時對存儲過程進行修改,對應用程序源代碼毫無影響。

存儲過程能實現較快的執行速度:如果某一操作包含大量的Transaction-SQL代碼或分別被多次執行,那麼存儲過程要比批處理的執行速度快很多。因爲存儲過程是預編譯的。在首次運行一個存儲過程時,優化器對其進行分析優化,並且給出最終被存儲在系統表中的執行計劃。而批處理的Transaction-SQL語句在每次運行時都要進行編譯和優化,速度相對要慢一些。

存儲過程能減少網絡流量:針對同一個數據庫對象的操作(如查詢、修改),如果這一操作所涉及的Transaction-SQL語句被組織成存儲過程,那麼當在客戶計算機上調用該存儲過程時,網絡中傳送的只是該調用語句,從而大大增加了網絡流量並降低了網絡負載。

存儲過程可被作爲一種安全機制來充分利用:系統管理員通過執行某一存儲過程的權限進行限制,能夠實現對相應的數據的訪問權限的限制,避免了非授權用戶對數據的訪問,保證了數據的安全。

索引

索引(Index)是幫助MySQL高效獲取數據的數據結構;在數據之外,數據庫系統還維護着滿足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,可以在這些數據結構上實現高級查找算法,提高查詢速度,這種數據結構,就是索引。

B-Tree 索引:最常見的索引類型,大部分引擎都支持B樹索引。

HASH 索引:只有Memory引擎支持,使用場景簡單。

R-Tree 索引(空間索引):空間索引是MyISAM的一種特殊索引類型,主要用於地理空間數據類型。

Full-text (全文索引):全文索引也是MyISAM的一種特殊索引類型,主要用於全文索引,InnoDB從MySQL5.6版本提供對全文索引的支持。

事物是什麼?

事務(Transaction)是併發控制的基本單位。所謂的事務,它是一個操作序列,由一條或者多條sql語句組成,這些操作要麼都執行,要麼都不執行,它是一個不可分割的工作單位。

acid特性?

原子性(Atomicity):指整個數據庫事務是不可分割的工作單位。只有事務中所有的數據庫操作都執行成功,整個事務的執行纔算成功。事務中任何一個sql語句執行失敗,那麼已經執行成功的sql語句也必須撤銷,數據庫狀態應該退回到執行事務前的狀態。

一致性(Consistency):事務應確保數據庫的狀態從一個一致狀態轉變爲另一個一致狀態。一致狀態的含義是數據庫中的數據應滿足完整性約束,也就是說在事務開始之前和事務結束以後,數據庫的完整性約束沒有被破壞

隔離性(Isolation):隔離性也叫做併發控制、可串行化或者鎖。事務的隔離性要求每個讀寫事務的對象與其它事務的操作對象能相互分離,即該事務提交前對其它事務都不可見,這通常使用鎖來實現多個事務併發執行時,一個事務的執行不應影響其他事務的執行。

持久性(Durability):表示事務一旦提交了,其結果就是永久性的,也就是數據就已經寫入到數據庫了,如果發生了宕機等事故,數據庫也能將數據恢復。

數據庫中的“主屬性”、“碼”、“主碼”的區別是什麼?

在數據庫的表(關係)中能夠用於唯一區分開每個記錄(元組)的屬性或屬性的集合,我們稱之爲碼(候選碼)。

當我們指定其中一個用來區分開每個記錄(元組)的碼爲主碼。

主屬性是指包含在候選碼中的屬性。

換句話說:主碼和碼的關係就像班長和班長候選人之間的關係。

每個班長候選人,我們可稱之爲主屬性,只不過在數據庫中,候選碼可能是多個屬性共同組成的。

設計模式

參考資料:《設計模式之禪》,簡要了解一下即可

23種設計模式

單例模式程序的實現

軟件工程

軟件的健壯性是指什麼?

健壯性是指程序可以適應正常和非正常的運行環境,都可以正確地運行;隨着業務量的增加,不會出現阻塞和不可用的情況。

影響程序健壯性的因素

沒有容錯控制

2.執行耗時的操作

執行復雜的任務

數據不一致

算法效率低

不能應對大流量衝擊

什麼是正確性

不可重入的任務被重入

沒有前置狀態判定

沒有遵守“受理—處理—關閉”AHC模型

沒有遵守“申請—前置審批—審批—善後—完成”RPC模型

數據庫復製造成數據延遲

智力題

100層樓,2個雞蛋,雞蛋從某一個臨界樓層丟下會摔碎,請設計方案,能用最小的次數找到臨界樓層

用3,4,5,6,7,8組成不重複的4位奇數,按照從小到大的順序排序,第a62個數字是?

首先是奇數的話,末位只能是3,5,7中的一種,則有$C_{3}^{1}$種方法。前面3個數是$A_{5}^{3}$排列方法,那麼總的方法數爲$C_{3}^{1}×A_{5}^{3} = 180$種方法,組成的奇數按照從小到大排序。當第一位是3的時候,末位一定是5或者7,那麼這樣的數一共有$C_{2}^{1}×A_{4}^{2} = 24$種方法,當第一位是4的時候,末位一定是3或者5或者7,這樣的數一共有$C_{3}^{1}×A_{4}^{2} = 36$種方法,那麼這裏一共就有$24+36=60$種方法,當第一位是5的時候,末位一定是3或者7,取較小的數,第二位是3,最後一位是7,那麼第61個數是5347,第62個數爲5367.

24點遊戲

25匹馬,5個跑道,如何通過最少的比賽次數確定前3名?

一家人過橋問題

相关文章