嵌入式筆試
- 一、行程與執行緒
- 1、什么是行程、執行緒,有什么區別?
- 2、多行程、多執行緒的優缺點
- 3、什么時候用行程,什么時候用執行緒
- 4、多行程、多執行緒同步(通訊)的方法
- 5、行程執行緒的狀態轉換圖
- 6、父行程、子行程
- 7、說明什么是背景關系切換?
- 二、C/C++題目
- 1、``new``和``malloc``
- 2、在1G記憶體的計算機中能否``malloc``(1.2G)?為什么?(2021浙江大華二面問題)
- 3 、``extern”C”`` 的作用
- 4、``strcat``、``strncat``、``strcmp``、``strcpy``哪些函式會導致記憶體溢位?如何改進?(2021浙江大華二面問題)
- 5 、``static``的用法(定義和用途)(必考)
- 6、``const``的用法(定義和用途)(必考)
- 7、``volatile``作用和用法
- 8、``const``常量和``#define``的區別(編譯階段、安全性、記憶體占用等)
- 9、變數的作用域(全域變數和區域變數)
- 10、``sizeof`` 與``strlen`` (字串,陣列)
- 11、經典的``sizeof(struct)``和``sizeof(union)``記憶體對齊
- 12、``inline``函式
- 13、記憶體四區,什么變數分別存盤在什么區域,堆上還是堆疊上,
- 14、使用32位編譯情況下,給出判斷所使用機器大小端的方法,
- 15、用變數a給出下面的定義
- 16、與或非,異或,運算子優先級
- 三、網路編程
- 1 、``TCP``、``UDP``的區別
- 2 、``TCP``、``UDP``的優缺點
- 3 、``TCP``、``UDP``適用場景
- 4、 ``TCP``為什么是可靠連接?
- 5、``OSI``典型網路模型,簡單說說有哪些?
- 6、三次握手、四次揮手
- 四、常見演算法
- 1、十種常見排序演算法可以分為兩大類:
- 2、演算法優劣評價術語
- 五、Linux作業系統題目
- 1、 Linux內核的組成部分
- 2、Linux系統的組成部分
- 3、用戶空間與內核通信方式有哪些?
- 4、系統呼叫與普通函式呼叫的區別
- 5、內核態,用戶態的區別
- 6、 bootloader、內核 、根檔案的關系
- 7 、Bootloader啟動的兩個階段:
- 8、 linux下檢查記憶體狀態的命令
- 9 、一個程式從開始運行到結束的完整程序(四個程序)
- 10、什么是堆,堆疊,記憶體泄漏和記憶體溢位?
- 11、死鎖的原因、條件
- 12、硬鏈接與軟鏈接
- 13、計算機中,32bit與64bit有什么區別
- 14、中斷和例外的區別
- 15、中斷怎么發生,中斷處理流程
- 16、 Linux 作業系統掛起、休眠、關機相關命令
- 17、說一個linux下編譯優化選項:
- 18、在有資料cache情況下,DMA資料鏈路為:
- 19、linux命令
- 20、硬實時系統和軟實時系統
- 21、MMU基礎
一、行程與執行緒
1、什么是行程、執行緒,有什么區別?
行程是資源(CPU、記憶體等)分配的基本單位,執行緒是CPU調度和分配的基本單位(程式執行的最小單位),同一時間,如果CPU是單核,只有一個行程在執行,所謂的并發執行,也是順序執行,只不過由于切換速度太快,你以為這些行程在同步執行而已,多核CPU可以同一時間點有多個行程在執行,
2、多行程、多執行緒的優缺點
說明:一個行程由行程控制塊、資料段、代碼段組成,行程本身不可以運行程式,而是像一個容器一樣,先創建出一個主執行緒,分配給主執行緒一定的系統資源,這時候就可以在主執行緒開始實作各種功能,當我們需要實作更復雜的功能時,可以在主執行緒里創建多個子執行緒,多個執行緒在同一個行程里,利用這個行程所擁有的系統資源合作完成某些功能,
優缺點:1)一個行程死了不影響其他行程,一個執行緒崩潰很可能影響到它本身所處的整個行程,
2)創建多行程的系統花銷大于創建多執行緒,
3)多行程通訊因為需要跨越行程邊界,不適合大量資料的傳送,適合小資料或者密集資料的傳送,多執行緒無需跨越行程邊界,適合各執行緒間大量資料的傳送,并且多執行緒可以共享同一行程里的共享記憶體和變數,
3、什么時候用行程,什么時候用執行緒
1)創建和銷毀較頻繁使用執行緒,因為創建行程花銷大,
2)需要大量資料傳送使用執行緒,因為多執行緒切換速度快,不需要跨越行程邊界,
3)安全穩定選行程;快速頻繁選執行緒;
4、多行程、多執行緒同步(通訊)的方法
行程間通訊:
(1)有名管道/無名管道(2)信號(3)共享記憶體(4)訊息佇列(5)信號量(6)socket
執行緒通訊(鎖):
(1)信號量(2)讀寫鎖(3)條件變數(4)互斥鎖(5)自旋鎖
5、行程執行緒的狀態轉換圖
(1)就緒狀態:行程已獲得除CPU外的所有必要資源,只等待CPU時的狀態,一個系統會將多個處于就緒狀態的行程排成一個就緒佇列,
(2)執行狀態:行程已獲CPU,正在執行,單處理機系統中,處于執行狀態的行程只一個;多處理機系統中,有多個處于執行狀態的行程,
(3)阻塞狀態:正在執行的行程由于某種原因而暫時無法繼續執行,便放棄處理機而處于暫停狀態,即行程執行受阻,(這種狀態又稱等待狀態或封鎖狀態)
通常導致行程阻塞的典型事件有:請求I/O,申請緩沖空間等,
一般,將處于阻塞狀態的行程排成一個佇列,有的系統還根據阻塞原因不同把這些阻塞集成排成多個佇列,

(1) 就緒→執行
處于就緒狀態的行程,當行程調度程式為之分配了處理機后,該行程便由就緒狀態轉變成執行狀態,
(2) 執行→就緒
處于執行狀態的行程在其執行程序中,因分配給它的一個時間片已用完而不得不讓出處理機,于是行程從執行狀態轉變成就緒狀態,
(3) 執行→阻塞
正在執行的行程因等待某種事件發生而無法繼續執行時,便從執行狀態變成阻塞狀態,
(4) 阻塞→就緒
處于阻塞狀態的行程,若其等待的事件已經發生,于是行程由阻塞狀態轉變為就緒狀態,
6、父行程、子行程
父行程呼叫fork()以后,克隆出一個子行程,子行程和父行程擁有相同內容的代碼段、資料段和用戶堆疊,父行程和子行程誰先執行不一定,看CPU,所以我們一般我們會設定父行程等待子行程執行完畢,
7、說明什么是背景關系切換?
你可以有很多角度,有行程背景關系,有中斷背景關系,
行程背景關系:一個行程在執行的時候,CPU的所有暫存器中的值、行程的狀態以及堆疊中的內容,當內核需要切換到另一個行程時,它需要保存當前行程的所有狀態,即保存當前行程的行程背景關系,以便再次執行該行程時,能夠恢復切換時的狀態,繼續執行,
中斷背景關系:由于觸發信號,導致CPU中斷當前行程,轉而去執行另外的程式,那么當前行程的所有資源要保存,比如堆疊和指標,保存過后轉而去執行中斷處理程式,快讀執行完畢回傳,回傳后恢復上一個行程的資源,繼續執行,這就是中斷的背景關系,
二、C/C++題目
1、new和malloc
做嵌入式,對于記憶體是十分在意的,因為可用記憶體有限,所以嵌入式筆試面試題目,記憶體的題目高頻,
1)malloc和free是c++/c語言的庫函式,需要頭檔案支持stdlib.h;new和delete是C++的關鍵字,不需要頭檔案,需要編譯器支持;
2)使用new運算子申請記憶體分配時,無需指定記憶體塊的大小,編譯器會根據型別資訊自行計算,而malloc則需要顯式地支持所需記憶體的大小,
3)new運算子記憶體分配成功時,回傳的是物件型別的指標,型別嚴格與物件匹配,無需進行型別轉換,故new是符合型別安全性的運算子,而malloc記憶體分配成功則是回傳void*,需要通過強制型別轉換將void*指標轉換成我們需要的型別,
4)new記憶體分配失敗時,會拋出bad_alloc例外,malloc分配記憶體失敗時回傳NULL,
2、在1G記憶體的計算機中能否malloc(1.2G)?為什么?(2021浙江大華二面問題)
答:是有可能申請1.2G的記憶體的,
決議:回答這個問題前需要知道malloc的作用和原理,應用程式通過malloc函式可以向程式的虛擬空間申請一塊虛擬地址空間,與物理記憶體沒有直接關系,得到的是在虛擬地址空間中的地址,之后程式運行所提供的物理記憶體是由作業系統完成的,
3 、extern”C” 的作用
我們可以在C++中使用C的已編譯好的函式模塊,這時候就需要用到extern”C”,也就是extern“C” 都是在c++檔案里添加的,
extern在鏈接階段起作用(四大階段:預處理--編譯--匯編--鏈接),
4、strcat、strncat、strcmp、strcpy哪些函式會導致記憶體溢位?如何改進?(2021浙江大華二面問題)
strcpy函式會導致記憶體溢位,
strcpy拷貝函式不安全,他不做任何的檢查措施,也不判斷拷貝大小,不判斷目的地址記憶體是否夠用,
char *strcpy(char *strDest,const char *strSrc)
strncpy拷貝函式,雖然計算了復制的大小,但是也不安全,沒有檢查目標的邊界,
strncpy(dest, src, sizeof(dest));
strncpy_s是安全的,
strcmp(str1,str2),是比較函式,若str1=str2,則回傳零;若str1<str2,則回傳負數;若str1>str2,則回傳正數,(比較字串)
strncat()主要功能是在字串的結尾追加n個字符,
char * strncat(char *dest, const char *src, size_t n);
strcat()函式主要用來將兩個char型別連接,例如:
char d[20]="Golden";
char s[20]="View";
strcat(d,s);
//列印d
printf("%s",d);
輸出 d 為 GoldenView (中間無空格)
延伸:
memcpy拷貝函式,它與strcpy的區別就是memcpy可以拷貝任意型別的資料,strcpy只能拷貝字串型別,
memcpy 函式用于把資源記憶體(src所指向的記憶體區域)拷貝到目標記憶體(dest所指向的記憶體區域);有一個size變數控制拷貝的位元組數;
函式原型:
void *memcpy(void *dest, void *src, unsigned int count);
5 、static的用法(定義和用途)(必考)
1)用static修飾區域變數:使其變為靜態存盤方式(靜態資料區),那么這個區域變數在函式執行完成之后不會被釋放,而是繼續保留在記憶體中,
2)用static修飾全域變數:使其只在本檔案內部有效,而其他檔案不可連接或參考該變數,
3)用static修飾函式:對函式的連接方式產生影響,使得函式只在本檔案內部有效,對其他檔案是不可見的(這一點在大工程中很重要很重要,避免很多麻煩,很常見),這樣的函式又叫作靜態函式,使用靜態函式的好處是,不用擔心與其他檔案的同名函式產生干擾,另外也是對函式本身的一種保護機制,
6、const的用法(定義和用途)(必考)
const主要用來修飾變數、函式形參和類成員函式:
1)用const修飾常量:定義時就初始化,以后不能更改,
2)用const修飾形參:func(const int a){};該形參在函式里不能改變,
3)用const修飾類成員函式:該函式對成員變數只能進行只讀操作,就是const類成員函式是不能修改成員變數的數值的,
被const修飾的東西都受到強制保護,可以預防意外的變動,能提高程式的健壯性,
參考一個大佬的回答:
我只要一聽到被面試者說:“const意味著常數”,我就知道我正在和一個業余者打交道,去年Dan Saks已經在他的文章里完全概括了const的所有用法,因此ESP(譯者:Embedded Systems Programming)的每一位讀者應該非常熟悉const能做什么和不能做什么.如果你從沒有讀到那篇文章,只要能說出const意味著"只讀"就可以了,盡管這個答案不是完全的答案,但我接受它作為一個正確的答案,如果應試者能正確回答這個問題,我將問他一個附加的問題:下面的宣告都是什么意思?
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前兩個的作用是一樣,a是一個常整型數,
第三個意味著a是一個指向常整型數的指標(也就是,整型數是不可修改的,但指標可以),
第四個意思a是一個指向整型數的常指標(也就是說,指標指向的整型數是可以修改的,但指標是不可修改的),
最后一個意味著a是一個指向常整型數的常指標(也就是說,指標指向的整型數是不可修改的,同時指標也是不可修改的),
7、volatile作用和用法
一個定義為volatile的變數是說這變數可能會被意想不到地改變,這樣,編譯器就不會去假設這個變數的值了,精確地說就是,優化器在用到這個變數時必須每次都小心地重新讀取這個變數在記憶體中的值,而不是使用保存在暫存器里的備份(雖然讀寫暫存器比讀寫記憶體快),
回答不出這個問題的人是不會被雇傭的,這是區分C程式員和嵌入式系統程式員的最基本的問題,搞嵌入式的家伙們經常同硬體、中斷、RTOS等等打交道,所有這些都要求用到volatile變數,不懂得volatile的內容將會帶來災難,
以下幾種情況都會用到volatile:
1、并行設備的硬體暫存器(如:狀態暫存器)
2、一個中斷服務子程式中會訪問到的非自動變數
3、多執行緒應用中被幾個任務共享的變數
8、const常量和#define的區別(編譯階段、安全性、記憶體占用等)
用#define max 100 ; 定義的常量是沒有型別的(不進行型別安全檢查,可能會產生意想不到的錯誤),所給出的是一個立即數,編譯器只是把所定義的常量值與所定義的常量的名字聯系起來,define所定義的宏變數在預處理階段的時候進行替換,在程式中使用到該常量的地方都要進行拷貝替換;
用const int max = 255 ; 定義的常量有型別(編譯時會進行型別檢查)名字,存放在記憶體的靜態區域中,在編譯時確定其值,在程式運行程序中const變數只有一個拷貝,而#define所定義的宏變數卻有多個拷貝,所以宏定義在程式運行程序中所消耗的記憶體要比const變數的大得多,
9、變數的作用域(全域變數和區域變數)
全域變數:在所有函式體的外部定義的,程式的所在部分(甚至其它檔案中的代碼)都可以使用,全域變數不受作用域的影響(也就是說,全域變數的生命期一直到程式的結束),
區域變數:出現在一個作用域內,它們是局限于一個函式的,區域變數經常被稱為自動變數,因為它們在進入作用域時自動生成,離開作用域時自動消失,關鍵字auto可以顯式地說明這個問題,但是區域變數默認為auto,所以沒有必要宣告為auto,
區域變數可以和全域變數重名,在區域變數作用域范圍內,全域變數失效,采用的是區域變數的值,
10、sizeof 與strlen (字串,陣列)
1.如果是陣列
#include<stdio.h>
int main()
{
int a[5]={1,2,3,4,5};
printf(“sizeof 陣列名=%d\n”,sizeof(a));
printf(“sizeof *陣列名=%d\n”,sizeof(*a));
}
運行結果
sizeof 陣列名=20
sizeof *陣列名=4
2.如果是指標,sizeof只會檢測到是指標的型別,指標都是占用4個位元組的空間(32位機),
sizeof是什么?是一個運算子,也是關鍵字,就不是一個函式,這和strlen()不同,strlen()是一個函式,
那么sizeof的作用是什么?回傳一個物件或者型別所占的記憶體位元組數,我們會對sizeof()中的資料或者指標做運算嗎?基本不會,例如sizeof(1+2.0),直接檢測到其中型別是double,即是sizeof(double) = 8,如果是指標,sizeof只會檢測到是指標的型別,指標都是占用4個位元組的空間(32位機),
char *p = "sadasdasd";
sizeof(p):4
sizeof(*p):1//指向一個char型別的
除非使用strlen(),僅對字串有效,直到’\0’為止了,計數結果不包括\0,
要是非要使用sizeof來得到指向內容的大小,就得使用陣列名才行, 如
char a[10];
sizeof(a):10 //檢測到a是一個陣列的型別,

關于strlen(),它是一個函式,考察的比較簡單:
strlen “\n\t\tag\AAtang”
答案:11
11、經典的sizeof(struct)和sizeof(union)記憶體對齊
記憶體對齊作用:
1.平臺原因(移植原因):不是所有的硬體平臺都能訪問任意地址上的任意資料的;某些硬體平臺只能在某些地址處取某些特定型別的資料,否則拋出硬體例外,
2.性能原因:資料結構(尤其是堆疊)應該盡可能地在自然邊界上對齊,原因在于,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問,
結構體struct記憶體對齊的3大規則:
1.對于結構體的各個成員,第一個成員的偏移量是0,排列在后面的成員其當前偏移量必須是當前成員型別的整數倍;
2.結構體內所有資料成員各自記憶體對齊后,結構體本身還要進行一次記憶體對齊,保證整個結構體占用記憶體大小是結構體內最大資料成員的最小整數倍;
3.如程式中有#pragma pack(n)預編譯指令,則所有成員對齊以n位元組為準(即偏移量是n的整數倍),不再考慮當前型別以及最大結構體內型別,
#pragma pack(1)
struct fun{
int i;
double d;
char c;
};
//sizeof(fun) = 13
struct CAT_s
{
int ld;
char Color;
unsigned short Age;
char *Name;
void(*Jump)(void);
}Garfield;
1.使用32位編譯,int占4, char 占1, unsigned short 占2,char* 占4,函式指標占4個,由于是32位編譯是4位元組對齊,所以該結構體占16個位元組,(說明:按幾位元組對齊,是根據結構體的最長型別決定的,這里是int是最長的位元組,所以按4位元組對齊);
2.使用64位編譯 ,int占4, char 占1, unsigned short 占2,char* 占8,函式指標占8個,由于是64位編譯是8位元組對齊(說明:按幾位元組對齊,是根據結構體的最長型別決定的,這里是函式指標是最長的位元組,所以按8位元組對齊)所以該結構體占24個位元組,
//64位
struct C
{
double t; //8 1111 1111
char b; //1 1
int a; //4 0001111
short c; //2 11000000
};
sizeof(C) = 24; //注意:1 4 2 不能拼在一起
char是1,然后在int之前,地址偏移量得是4的倍數,所以char后面補三個位元組,也就是char占了4個位元組,然后int四個位元組,最后是short,只占兩個位元組,但是總的偏移量得是double的倍數,也就是8的倍數,所以short后面補六個位元組,
聯合體union記憶體對齊的2大規則:
1.找到占用位元組最多的成員;
2.union的位元組數必須是占用位元組最多的成員的位元組的倍數,而且需要能夠容納其他的成員,
//x64
typedef union {
long i;
int k[5];
char c;
}D
要計算union的大小,首先要找到占用位元組最多的成員,本例中是long,占用8個位元組,int k[5]中都是int型別,仍然是占用4個位元組的,然后union的位元組數必須是占用位元組最多的成員的位元組的倍數,而且需要能夠容納其他的成員,為了要容納k(20個位元組),就必須要保證是8的倍數的同時還要大于20個位元組,所以是24個位元組,
引申:位域(大疆筆試題)
C語言允許在一個結構體中以位為單位來指定其成員所占記憶體長度,這種以位為單位的成員稱為“位段”或稱“位域”( bit field) ,利用位段能夠用較少的位數存盤資料,一個位段必須存盤在同一存盤單元中,不能跨兩個單元,如果第一個單元空間不能容納下一個位段,則該空間不用,而從下一個單元起存放該位段,
1.位段宣告和結構體類似
2.位段的成員必須是int、unsigned int、signed int
3.位段的成員名后邊有一個冒號和一個數字
typedef struct_data{
char m:3;
char n:5;
short s;
union{
int a;
char b;
};
int h;
}_attribute_((packed)) data_t;
答案12
m和n一起,剛好占用一個位元組記憶體,因為后面是short型別變數,所以在short s之前,應該補一個位元組,所以m和n其實是占了兩個位元組的,然后是short兩個個位元組,加起來就4個位元組,然后聯合體占了四個位元組,總共8個位元組了,最后int h占了四個位元組,就是12個位元組了,
attribute((packed)) 取消對齊
GNU C的一大特色就是__attribute__機制,__attribute__可以設定函式屬性(Function Attribute)、變數屬性(Variable Attribute)和型別屬性(Type Attribute),
__attribute__書寫特征是:__attribute__前后都有兩個下劃線,并且后面會緊跟一對括弧,括弧里面是相應的__attribute__引數,
跨平臺通信時用到,不同平臺記憶體對齊方式不同,如果使用結構體進行平臺間的通信,會有問題,例如,發送訊息的平臺上,結構體為24位元組,接受訊息的平臺上,此結構體為32位元組(只是隨便舉個例子),那么每個變數對應的值就不對了,
不同框架的處理器對齊方式會有不同,這個時候不指定對齊的話,會產生錯誤結果,
12、inline函式
在C語言中,如果一些函式被頻繁呼叫,不斷地有函式入堆疊,即函式堆疊,會造成堆疊空間或堆疊記憶體的大量消耗,為了解決這個問題,特別的引入了inline修飾符,表示為行內函式,
大多數的機器上,呼叫函式都要做很多作業:呼叫前要先保存暫存器,并在回傳時恢復,復制實參,程式還必須轉向一個新位置執行C++中支持行內函式,其目的是為了提高函式的執行效率,用關鍵字 inline 放在函式定義(注意是定義而非宣告)的前面即可將函式指定為行內函式,行內函式通常就是將它在程式中的每個呼叫點上“行內地”展開,
行內是以代碼膨脹(復制)為代價,僅僅省去了函式呼叫的開銷,從而提高函式的執行效率,
13、記憶體四區,什么變數分別存盤在什么區域,堆上還是堆疊上,


文字常量區,叫.rodata,不可以改變,改變會導致段錯誤
int a0=1;
static int a1;
const static a2=0;
extern int a3;
void fun(void)
{
int a4;
volatile int a5;
return;
}
a0 :全域初始化變數;生命周期為整個程式運行期間;作用域為所有檔案;存盤位置為data段,
a1 :全域靜態未初始化變數;生命周期為整個程式運行期間;作用域為當前檔案;儲存位置為BSS段,
a2 :全域靜態變數
a3 :全域初始化變數;其他同a0,
a4 :區域變數;生命周期為fun函式運行期間;作用域為fun函式內部;儲存位置為堆疊,
a5 :區域易變變數;
14、使用32位編譯情況下,給出判斷所使用機器大小端的方法,

聯合體方法判斷方法:利用union結構體的從低地址開始存,且同一時間內只有一個成員占有記憶體的特性,大端儲存符合閱讀習慣,聯合體占用記憶體是最大的那個,和結構體不一樣,
a和c公用同一片記憶體區域,所以更改c,必然會影響a的資料,
#include<stdio.h>
int main(){
union w
{
int a;
char b;
}c;
c.a = 1;
if(c.b == 1)
printf("小端存盤\n");
else
printf("大端存盤\n");
return 0;
}
指標方法
通過將int強制型別轉換成char單位元組,p指向a的起始位元組(低位元組)
#include <stdio.h>
int main ()
{
int a = 1;
char *p = (char *)&a;
if(*p == 1)
{
printf("小端存盤\n");
}
else
{
printf("大端存盤\n");
}
return 0;
}
15、用變數a給出下面的定義
a) 一個整型數;
b)一個指向整型數的指標;
c)一個指向指標的指標,它指向的指標是指向一個整型數;
d)一個有10個整型的數組;
e)一個有10個指標的陣列,該指標是指向一個整型數;
f)一個指向有10個整型數陣列的指標;
g)一個指向函式的指標,該函式有一個整型引數并回傳一個整型數;
h)一個有10個指標的陣列,該指標指向一個函式,該函式有一個整型引數并回傳一個整型數
答案:
a)int a
b)int *a;
c)int **a;
d)int a[10];
e)int *a [10];
f) int a[10], *p=a;
g)int (*a)(int)
h) int( *a[10])(int)
16、與或非,異或,運算子優先級
sum=a&b<<c+a^c;
其中a=3,b=5,c=4(先加再移位再&再異或)答案4

三、網路編程
1 、TCP、UDP的區別
TCP—傳輸控制協議,提供的是面向連接、可靠的位元組流服務,當客戶和服務器彼此交換資料前,必須先在雙方之間建立一個TCP連接,之后才能傳輸資料,
UDP—用戶資料報協議,是一個簡單的面向資料報的運輸層協議,UDP不提供可靠性,它只是把應用程式傳給IP層的資料報發送出去,但是并不能保證它們能到達目的地,
1)TCP是面向連接的,UDP是面向無連接的
2)UDP程式結構較簡單
3)TCP是面向位元組流的,UDP是基于資料報的
4)TCP保證資料正確性,UDP可能丟包
5)TCP保證資料順序到達,UDP不保證
2 、TCP、UDP的優缺點
TCP優點:可靠穩定
TCP的可靠體現在TCP在傳輸資料之前,會有三次握手來建立連接,而且在資料傳遞時,有確認、視窗、重傳、擁塞控制機制,在資料傳完之后,還會斷開來連接用來節約系統資源,
TCP缺點:慢,效率低,占用系統資源高,易被攻擊
在傳遞資料之前要先建立連接,這會消耗時間,而且在資料傳遞時,確認機制、重傳機制、擁塞機制等都會消耗大量時間,而且要在每臺設備上維護所有的傳輸連接,然而,每個連接都會占用系統的CPU,記憶體等硬體資源,因為TCP有確認機制、三次握手機制,這些也導致TCP容易被利用,實作DOS、DDOS、CC等攻擊,
UDP優點:快,比TCP稍安全
UDP沒有TCP擁有的各種機制,是一種無狀態的傳輸協議,所以傳輸資料非常快,沒有TCP的這些機制,被攻擊利用的機會就少一些,但是也無法避免被攻擊,
UDP缺點:不可靠,不穩定
因為沒有TCP的這些機制,UDP在傳輸資料時,如果網路質量不好,就會很容易丟包,造成資料的缺失,
3 、TCP、UDP適用場景
TCP:傳輸一些對信號完整性,信號質量有要求的資訊,
UDP:對網路通訊質量要求不高時,要求網路通訊速度要快的場景,
4、 TCP為什么是可靠連接?
因為tcp傳輸的資料滿足3大條件,不丟失,不重復,按順序到達,
5、OSI典型網路模型,簡單說說有哪些?

6、三次握手、四次揮手
三次握手

1、TCP服務器行程先創建傳輸控制塊TCB,時刻準備接受客戶行程的連接請求,此時服務器就進入了LISTEN(監聽)狀態;
2、TCP客戶行程也是先創建傳輸控制塊TCB,然后向服務器發出連接請求報文,這是報文首部中的同部位SYN=1,同時選擇一個初始序列號seq=x ,此時,TCP客戶端行程進入了 SYN-SENT(同步已發送狀態)狀態,TCP規定,SYN報文段(SYN=1的報文段)不能攜帶資料,但需要消耗掉一個序號,
3、TCP服務器收到請求報文后,如果同意連接,則發出確認報文,確認報文中應該ACK=1,SYN=1,確認號是ack=x+1,同時也要為自己初始化一個序列號seq=y,此時,TCP服務器行程進入了SYN-RCVD(同步收到)狀態,這個報文也不能攜帶資料,但是同樣要消耗一個序號,
4、TCP客戶行程收到確認后,還要向服務器給出確認,確認報文的ACK=1,ack=y+1,自己的序列號seq=x+1,此時,TCP連接建立,客戶端進入ESTABLISHED(已建立連接)狀態,TCP規定,ACK報文段可以攜帶資料,但是如果不攜帶資料則不消耗序號,
5、當服務器收到客戶端的確認后也進入ESTABLISHED狀態,此后雙方就可以開始通信了,
四次揮手

1、客戶端行程發出連接釋放報文,并且停止發送資料,釋放資料報文首部,FIN=1,其序列號為seq=u(等于前面已經傳送過來的資料的最后一個位元組的序號加1),此時,客戶端進入FIN-WAIT-1(終止等待1)狀態,TCP規定,FIN報文段即使不攜帶資料,也要消耗一個序號,
2、服務器收到連接釋放報文,發出確認報文,ACK=1,ack=u+1,并且帶上自己的序列號seq=v,此時,服務端就進入了CLOSE-WAIT(關閉等待)狀態,TCP服務器通知高層的應用行程,客戶端向服務器的方向就釋放了,這時候處于半關閉狀態,即客戶端已經沒有資料要發送了,但是服務器若發送資料,客戶端依然要接受,這個狀態還要持續一段時間,也就是整個CLOSE-WAIT狀態持續的時間,
3、客戶端收到服務器的確認請求后,此時,客戶端就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發送連接釋放報文(在這之前還需要接受服務器發送的最后的資料),
4、服務器將最后的資料發送完畢后,就向客戶端發送連接釋放報文,FIN=1,ack=u+1,由于在半關閉狀態,服務器很可能又發送了一些資料,假定此時的序列號為seq=w,此時,服務器就進入了LAST-ACK(最后確認)狀態,等待客戶端的確認,
5、客戶端收到服務器的連接釋放報文后,必須發出確認,ACK=1,ack=w+1,而自己的序列號是seq=u+1,此時,客戶端就進入了TIME-WAIT(時間等待)狀態,注意此時TCP連接還沒有釋放,必須經過2? *?MSL(最長報文段壽命)的時間后,當客戶端撤銷相應的TCB后,才進入CLOSED狀態, 6、服務器只要收到了客戶端發出的確認,立即進入CLOSED狀態,同樣,撤銷TCB后,就結束了這次的TCP連接,可以看到,服務器結束TCP連接的時間要比客戶端早一些,
四、常見演算法
1、十種常見排序演算法可以分為兩大類:
非線性時間比較類排序:通過比較來決定元素間的相對次序,由于其時間復雜度不能突破O(nlogn),因此稱為非線性時間比較類排序,
線性時間非比較類排序:不通過比較來決定元素間的相對次序,它可以突破基于比較排序的時間下界,以線性時間運行,因此稱為線性時間非比較類排序,

2、演算法優劣評價術語
穩定性:
穩定:如果 a 原本在 b 前面,而 a = b,排序之后 a 仍然在 b 的前面;
不穩定:如果 a 原本在 b 的前面,而 a = b,排序之后 a 可能會出現在 b 的后面;
排序方式:
內排序:所有排序操作都在記憶體中完成,占用常數記憶體,不占用額外記憶體,
外排序:由于資料太大,因此把資料放在磁盤中,而排序通過磁盤和記憶體的資料傳輸才能進行,占用額外記憶體,
復雜度:
時間復雜度: 一個演算法執行所耗費的時間,
空間復雜度: 運行完一個程式所需記憶體的大小,


至于各種演算法的原理以及代碼實作,由于太多并且比較復雜,不在本文列出,但推薦兩本入門的書:《啊哈!演算法》、《大話資料結構》,電子版我會發在交流群里,
排序演算法很多,嵌入式要求的不會太多,你會冒泡排序、快速排序、插入排序就可以解決很多問題,難的比如動態規劃問題,圖的路徑問題,嵌入式考的比較少,純軟才會考這些,(大公司和獨角獸公司考的會相對難一些)
五、Linux作業系統題目
1、 Linux內核的組成部分
Linux內核主要由五個子系統組成:行程調度,記憶體管理,虛擬檔案系統,網路介面,行程間通信,

2、Linux系統的組成部分
Linux系統一般有4個主要部分:內核、shell、檔案系統和應用程式,


3、用戶空間與內核通信方式有哪些?
1)系統呼叫,用戶空間行程通過系統呼叫進入內核空間,訪問指定的內核空間資料;
2)驅動程式,用戶空間行程可以使用封裝后的系統呼叫介面訪問驅動設備節點,以和運行在內核空間的驅動程式通信;
3)共享記憶體mmap,在代碼中呼叫介面,實作內核空間與用戶空間的地址映射,在實時性要求很高的專案中為首選,省去拷貝資料的時間等資源,但缺點是不好控制;
4)copy_to_user()、copy_from_user(),是在驅動程式中呼叫介面,實作用戶空間與內核空間的資料拷貝操作,應用于實時性要求不高的專案中,
以及:
procfs(/proc)
sysctl (/proc/sys)
sysfs(/sys)
netlink 套介面
4、系統呼叫與普通函式呼叫的區別
系統呼叫:
1.使用INT和IRET指令,內核和應用程式使用的是不同的堆疊,因此存在堆疊的切換,從用戶態切換到內核態,從而可以使用特權指令操控設備,
2.依賴于內核,不保證移植性
3.在用戶空間和內核背景關系環境間切換,開銷較大
4.是作業系統的一個入口點
普通函式呼叫:
1.使用CALL和RET指令,呼叫時沒有堆疊切換
2.平臺移植性好
3.屬于程序呼叫,呼叫開銷較小
4.一個普通功能函式的呼叫
5、內核態,用戶態的區別
內核態,作業系統在內核態運行——運行作業系統程式
用戶態,應用程式只能在用戶態運行——運行用戶程式
當一個行程在執行用戶自己的代碼時處于用戶運行態(用戶態),此時特權級最低,為3級,是普通的用戶行程運行的特權級,大部分用戶直接面對的程式都是運行在用戶態,Ring3狀態不能訪問Ring0的地址空間,包括代碼和資料;當一個行程因為系統呼叫陷入內核代碼中執行時處于內核運行態(內核態),此時特權級最高,為0級,執行的內核代碼會使用當前行程的內核堆疊,每個行程都有自己的內核堆疊,
6、 bootloader、內核 、根檔案的關系
啟動順序:bootloader->linux kernel->rootfile->app
Bootloader全名為啟動引導程式,是第一段代碼,它主要用來初始化處理器及外設,然后呼叫Linux內核,
Linux內核在完成系統的初始化之后需要掛載某個檔案系統作為根檔案系統(RootFilesystem),然后加載必要的內核模塊,啟動應用程式,
(一個嵌入式Linux系統從軟體角度看可以分為四個部分:引導加載程式(Bootloader),Linux內核,檔案系統,應用程式,)
7 、Bootloader啟動的兩個階段:
Stage1:匯編語言
1)基本的硬體初始化(關閉看門狗和中斷,MMU(帶作業系統),CACHE,配置系統作業時鐘)
2)為加載stage2準備RAM空間
3)拷貝內核映像和檔案系統映像到RAM中 4)設定堆疊指標sp 5)跳到stage2的入口點
Stage2:c語言
1)初始化本階段要使用到的硬體設備(led uart等)
2)檢測系統的記憶體映射
3)加載內核映像和檔案系統映像
4)設定內核的啟動引數
嵌入式系統中廣泛采用的非易失性存盤器通常是Flash,而Bootloader就位于該存盤器的最前端,所以系統上電或復位后執行的第一段程式便是Bootloader,
8、 linux下檢查記憶體狀態的命令
1)查看行程:top
2)查看記憶體:free
3)cat /proc/meminfo
4)vmstat
假如一個公司服務器有很多用戶,你使用top命令,可以看到哪個同事在使用什么命令,做什么事情,占用了多少CPU,
9 、一個程式從開始運行到結束的完整程序(四個程序)
預處理(Pre-Processing)、編譯(Compiling)、匯編(Assembling)、鏈接(Linking)
10、什么是堆,堆疊,記憶體泄漏和記憶體溢位?
堆疊由系統操作,程式員不可以操作,
所以記憶體泄漏是指堆記憶體的泄漏,堆記憶體是指程式從堆中分配的,大小任意的(記憶體塊的大小可以在程式運行期決定),使用完后必須顯式釋放的記憶體,應用程式一般使用malloc,new等函式從堆中分配到一塊記憶體,使用完后,程式必須負責相應的呼叫free或delete釋放該記憶體塊,否則,這塊記憶體就不能被再次使用,
記憶體溢位:你要求分配的記憶體超出了系統能給你的,系統不能滿足需求,于是產生溢位,
記憶體越界:向系統申請了一塊記憶體,而在使用記憶體時,超出了申請的范圍(常見的有使用特定大小陣列時發生記憶體越界)
記憶體溢位問題是 C 語言或者 C++ 語言所固有的缺陷,它們既不檢查陣列邊界,又不檢查型別可靠性(type-safety),眾所周知,用
C/C++ 語言開發的程式由于目標代碼非常接近機器內核,因而能夠直接訪問記憶體和暫存器,這種特性大大提升了 C/C++
語言代碼的性能,只要合理編碼,C/C++ 應用程式在執行效率上必然優于其它高級語言,然而,C/C++
語言導致記憶體溢位問題的可能性也要大許多,
11、死鎖的原因、條件
產生死鎖的原因主要是:
(1) 因為系統資源不足, (2) 行程運行推進的順序不合適, (3) 資源分配不當等,
如果系統資源充足,行程的資源請求都能夠得到滿足,死鎖出現的可能性就很低,否則就會因爭奪有限的資源而陷入死鎖,其次,行程運行推進順序與速度不同,也可能產生死鎖,
這四個條件是死鎖的必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖,
(1) 互斥條件:一個資源每次只能被一個行程使用,
(2) 請求與保持條件:一個行程因請求資源而阻塞時,對已獲得的資源保持不放,
(3)不剝奪條件:行程已獲得的資源,在末使用完之前,不能強行剝奪,
(4) 回圈等待條件:若干行程之間形成一種頭尾相接的回圈等待資源關系,
12、硬鏈接與軟鏈接
鏈接操作實際上是給系統中已有的某個檔案指定另外一個可用于訪問它的名稱,對于這個新的檔案名,我們可以為之指定不同的訪問權限,以控制對資訊的共享和安全性的問題,如果鏈接指向目錄,用戶就可以利用該鏈接直接進入被鏈接的目錄而不用打一大堆的路徑名,而且,即使我們洗掉這個鏈接,也不會破壞原來的目錄,
1)硬鏈接
硬鏈接只能參考同一檔案系統中的檔案,它參考的是檔案在檔案系統中的物理索引(也稱為inode),當您移動或洗掉原始檔案時,硬鏈接不會被破壞,因為它所參考的是檔案的物理資料而不是檔案在檔案結構中的位置,硬鏈接的檔案不需要用戶有訪問原始檔案的權限,也不會顯示原始檔案的位置,這樣有助于檔案的安全,如果您洗掉的檔案有相應的硬鏈接,那么這個檔案依然會保留,直到所有對它的參考都被洗掉,
2)軟鏈接(符號鏈接)
軟連接,其實就是新建立一個檔案,這個檔案就是專門用來指向別的檔案的(那就和windows 下的快捷方式的那個檔案有很接近的意味),軟連接產生的是一個新的檔案,但這個檔案的作用就是專門指向某個檔案的,刪了這個軟連接檔案,那就等于不需要這個連接,和原來的存在的物體原檔案沒有任何關系,但洗掉原來的檔案,則相應的軟連接不可用,
13、計算機中,32bit與64bit有什么區別
64bit計算主要有兩大優點:可以進行更大范圍的整數運算;可以支持更大的記憶體,
64位作業系統下的虛擬記憶體空間大小:地址空間大小不是2^32, 也不是2^64, 而一般是2^48, 因為并不需要2^64 那么大的尋址空間,過大的空間只會造成資源的浪費,所以64位Linux一般使用48位表示虛擬空間地址,40位標識物理地址,
14、中斷和例外的區別
內中斷:同步中斷(例外)是由cpu內部的電信號產生的中斷,其特點為當前執行的指令結束后才轉而產生中斷,由于有cpu主動產生,其執行點必然是可控的,
外中斷:異步中斷是由cpu的外設產生的電信號引起的中斷,其發生的時間點不可預期,
15、中斷怎么發生,中斷處理流程
請求中斷→回應中斷→關閉中斷→保留斷點→中斷源識別→保護現場→中斷服務子程式→恢復現場→中斷回傳,

16、 Linux 作業系統掛起、休眠、關機相關命令
關機命令有halt, init 0, poweroff ,shutdown -h 時間,其中shutdown是最安全的,
重啟命令有reboot,init 6,,shutdow -r時間
在linux命令中reboot是重新啟動,shutdown -r now是立即停止然后重新啟動,
17、說一個linux下編譯優化選項:
加:-o
18、在有資料cache情況下,DMA資料鏈路為:
外設-DMA-DDR-cache-CPU
19、linux命令
1、改變檔案屬性的命令:chmod (chmod 777 /etc/squid
運行命令后,squid檔案夾(目錄)的權限就被修改為777(可讀可寫可執行))
2、查找檔案中匹配字串的命令:grep
3、查找當前目錄:pwd
4、洗掉目錄:rm -rf 目錄名
5、洗掉檔案:rm 檔案名
6、創建目錄(檔案夾):mkdir
7、創建檔案:touch
8、vi和vim 檔案名也可以創建
9、解壓:tar -xzvf 壓縮包
打包:tar -cvzf 目錄(檔案夾)
10、查看行程對應的埠號
1、先查看行程pid
ps -ef | grep 行程名
2、通過pid查看占用埠
netstat -nap | grep 行程pid
20、硬實時系統和軟實時系統
軟實時系統:
Windows、Linux系統通常為軟實時,當然有補丁可以將內核做成硬實時的系統,不過商用沒有這么做的,
硬實時系統:
對時間要求很高,限定時間內不管做沒做完必須回傳,
VxWorks,uCOS,FreeRTOS,WinCE,RT-thread等實時系統;
21、MMU基礎
現代作業系統普遍采用虛擬記憶體管理(Virtual Memory Management) 機制,這需要MMU( Memory Management Unit,記憶體管理單元) 的支持,有些嵌入式處理器沒有MMU,則不能運行依賴于虛擬記憶體管理的作業系統,
也就是說:作業系統可以分成兩類,用MMU的、不用MMU的,
用MMU的是:Windows、MacOS、Linux、Android;
不用MMU的是:FreeRTOS、VxWorks、UCOS……
與此相對應的:CPU也可以分成兩類,帶MMU的、不帶MMU的,
帶MMU的是:Cortex-A系列、ARM9、ARM11系列;
不帶MMU的是:Cortex-M系列……(STM32是M系列,沒有MMU,不能運行Linux,只能運行一些UCOS、FreeRTOS等等),
MMU就是負責虛擬地址(virtual address)轉化成物理地址(physical address),轉換程序比較復雜,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/265115.html
標籤:其他
上一篇:網路編程那些躲不過的小基礎
下一篇:Go:簡介和特點
