1. 程式人生 > >入職作業總結(1)

入職作業總結(1)

收到網易的入職前作業,感覺都費勁(捂臉)。學習之餘做點筆記吧。
這部分主要涉及伺服器端的作業:用Python完成一個聊天視窗,以及若干附加的功能。

在看python文件時候注意到了兩個地址簇或者叫介面(因為直接影響了通訊協議):AF_INETAF_UNIX。查閱到資料Socket通訊中AF_INET 和 AF_UNIX域的區別,最關鍵的一點:AF_INET不僅可以用作本機的跨程序通訊,同樣的可以用於不同機器之間的通訊,其就是為了在不同機器之間進行網路互聯傳遞資料而生。而AF_UNIX則只能用於本機內程序之間的通訊。

SCTP協議與TCP和UDP協議同樣位於傳輸層,在客戶和伺服器之間提供關聯

,並保證可靠、排序、流量控制以及全雙工的資料傳輸。關聯指代兩個系統間的一次通訊,可能涉及不止兩個地址
SCTP能在連線的端點之間提供多個流,每個流各自可靠按序遞送訊息。與TCP不同,一個流上某個訊息的丟失不會阻塞其他流的訊息投遞,而TCP需要等待該丟失的資料被修復,否則一直被阻塞。SCTP還支援單個端點擁有多個IP地址。在建立連線後,如果某個IP通路之間發生故障,協議就可以切換到該端點的另一個地址來規避故障。
SCTP在建立連線時,採用四路握手的方式進行。簡單來說,在客戶端第一次傳送連線建立請求後,伺服器會返回一個帶有cookie的應答。隨後客戶端再附帶上cookie傳送一次請求,在伺服器相應後,則成功建立連線。四路握手結束後,兩端各選擇一個主目的地址
用作資料傳送到的目的地。
SCTP在斷開連線時沒有類似於TCP的TIME_WAIT狀態,因為SCTP使用了驗證標記cookie。因此,新/舊連線之間可以通過該標記來進行區分。

套接字地址結構

POSIX中對IPv4地址結構定義在<netinet/in.h>中,具體如下:

struct in_addr {
        in_addr_t s_addr   //通常是32位無符號整數,網路位元組序地址
}
struct sockaddr_in{
    uint8_t     sin_len;
    sa_family_t sin_family;     //8或16位無符號整數,表示地址結構的地址族,IPv4SHI AF_INET,IPv6是AF_INET6
in_port_t sin_port; //一般為uint16_t,即16位無符號整數 struct in_addr sin_addr; char sin_zero[8]; }

POSIX規範實際**只需要這個結構中的3個欄位:s_addrsin_familysin_port

其中有趣的一點,in_addr是一個結構體,即便它內部只有一個整數,這是有歷史原因的。早在地址被劃分成A、B、C三類的時期,in_addr被定義為多種結構的聯合,從而允許使用者訪問地址中的每4個位元組,便於或許所需的地址。後來CIDR的出現,這種劃分方式淡出了歷史舞臺,但這種結構保留了下來。

不同套接字的地址結構

不同套接字的地址結構
圖中最右側的儲存是指作為IPv6套接字API一部分而定義的新的通用套接字。它克服了sockaddr的一些缺點,用以取代sockaddr,定義在<netinet/in.h>中。

IPv4地址中的長度欄位是隨著4.3BSD Reno版本增加的。要是長度欄位在最原始的套接字API中就提供了,那麼套接字函式就不在需要長度引數——例如bindconnect函式的第三個引數。結構的大小可以包含在結構的長度欄位中(有點類似於STL對string的處理方式)

值-結果引數

1.從程序到核心傳遞套接字地址結構的函式有3個:bindconnectsendto。這些函式的一個引數是指向某個套接字地址結構的指標,另一個引數是該結構的整數大小
2.從核心到程序傳遞套接字地址結構的函式有4個:acceptrecvfromgetsocknamegetpeername。這四個函式的其中兩個引數是指向某個套接字地址結構的指標和指向該結構大小的整數變數的指標

把套接字地址結構大小這個引數從一個整數改為指向某個整數變數的指標,其原因在於:當函式被呼叫時,結構大小是一個值,它告訴核心該結構的大小,這樣核心在寫該結構時不至於越界;當函式返回時,結構大小又是一個結果,它告訴核心在該結構中究竟儲存了多少資訊。

從核心到程序傳遞套接字地址結構
如果套接字地址結構是固定長度的(前一張圖)如sockaddr_in,則從核心返回的值總是對應的固定長度。但對於sockaddr_un這類長度可變的套接字地址結構,返回值可能與傳入的值不同。

位元組排序和轉換函式

寫在前面:“大端”和“小端”的大致意思很多人都懂,但具體大端是高位在記憶體高地址還是低地址經常讓人混淆。《Unix網路程式設計》書中有一個解釋,我覺得比較清晰易理解:

“小端”和“大端”表示多個位元組值的哪一端(大或小)儲存在該值的起始地址。

值的大端小端,按照字面理解,顯然“大端”表示高位,“小端”表示低位。記憶體中的起始地址肯定是指記憶體中地址較低的位。

網路協議使用大端位元組序來傳送多位元組整數,如16位的埠號和32位的IPv4地址。位元組序轉換有以下4個函式:

uint16_t htons(uint16_t host16bitvalue);
uint32_t htonl(uint32_t host32bitvalue);
uint16_t ntohs(uint16_t net16bitvalue);
uint32_t ntohl(uint32_t net32bitvalue);

函式名中,h代表host,n代表network,s代表short,l代表long。這些命名是4.2BSD使其的產物。如今即使長整形佔64位,htonlntohl操作的仍是32位的值

此外有幾個地址轉換函式,將地址在習慣的點分十進位制字串與32位網路位元組序二進位制數值(針對IPv4)之間轉換。
隨著IPv6出現又天劍了幾個新的函式,並具有對IPv4的相容性,因此推薦使用。具體如下:

#include <arpa/inet.h>
int inet_pton(int family, const char *strptr, void *addrptr);
const char* inet_ntop(int family, const void *addrptr, char *strptr, size_t len);

其中pn分別代表表達(presentation)數值(numeric)。兩個函式中family既可以是AF_INET也可以是AF_INET6inet_pton()將字串式的地址轉換為二進位制結果儲存於*addrptr中,如果成功返回1,否則返回0inet_ntop()進行相反的轉換,len幫助制定目標儲存空間的大小避免溢位。如果len太小,則**會返回一個空指標,並置errnoENOSPC

close()函式

close一個TCP套接字的預設行為是把該套接字標記為已關閉,然後立刻返回呼叫程序。該套接字描述符不能再由呼叫程序使用。也就是不能再在該套接字上呼叫readwrite。(不過TCP協議仍將傳送已排隊等待發送到對端的資料),然後考慮關閉連線。這裡說考慮是因為,檔案或套接字是採用引用計數的方式進行管理。它是當前開啟著的引用該檔案或套接字的描述符的個數。例如,當伺服器接到一個請求時,可以採用如下處理方式:

for(; ; ){
    connfd = accept(listenfd, ...);
    if( (pid = fork() )== 0){
        close(listenfd);            //在子程序中關閉 監聽套接字
        do_something(connfd);
        close(connfd);              //可省略,因為exit()會關閉所有描述符
        exit(0);
    }
    close(connfd);                 //在父程序中關閉 已連線套接字
}    

這段程式碼在父程序和子程序中分別關閉了一個自己不需要的套接字描述符,但不會立刻引起TCP的私分組連線終止序列,這是因為該描述符還被其他程序佔用著,沒有減少到0。
如果我們確實想在某個TCP連線上傳送一個FIN,那麼可以使用shutdown()函式代替close
另外還得注意,(在上述父子程序的模式中)父程序必須對每個由accept()返回的已連線套接字都呼叫close(),否則,父程序終將耗盡所有的可用描述符(因為每個程序可用的開啟著的描述符是有限的),更重要的是,這些客戶連線都不會被終止,因為父程序一直開啟著對應的已連線套接字。

POSIX 訊號處理

訊號有時也稱為軟中斷。訊號可以:

  • 由一個程序發給另一個程序(或自身)
  • 由核心發給某個程序

正常程式中,由父程序派生的子程序完成退出後,不會自動消失,而是向父程序傳送一個SIGCHLD訊號。該訊號的預設處理是被忽略,這時子程序會進入僵死狀態,從而導致系統資源無法回收被浪費。
我們可以提供訊號處理函式來處理捕獲到的訊號(除了SIGKILLSIGSTOP),一般採用呼叫sigaction()signal()函式來設定訊號處理函式。

POSIX上的訊號處理有以下特點:

  • 一旦安裝了訊號處理函式,就一直安裝著(這裡我記得,僅限於程序內部,不同程序/重啟程序時恢復系統預設狀態)
  • 在一個訊號處理函式執行期間,正被遞交的訊號(即:同一個型別的訊號)是阻塞的,而且,呼叫sigaction函式中的sa_mask引數制定的任何額外訊號也被阻塞(除非把sa_mask置為空,則只有被捕獲的訊號被阻塞)
  • 如果一個訊號在被阻塞期間產生了一次或多次,那麼該訊號在被解除阻塞後只遞交一次

另外,值得注意的是,在accept(慢系統呼叫——指可能永遠阻塞的系統呼叫)期間捕獲訊號並轉到訊號處理函式。該函式退出後,核心就會使accept返回一個EINTR錯誤(被中斷的系統呼叫),因此父程序需要處理這項錯誤。

wait和waitpid函式

pid_t wait(int *statlc);
pid_t waitpid(pid_t pid, int *statloc, int options);

這兩個函式均返回兩個值:已終止的子程序PID,和通過statloc指標(如果不為NULL)返回的程序終止狀態(整數)。我們可以呼叫特定的巨集來檢查終止狀態。

  • WIFEXITED(status)這個巨集用來指出子程序是否為正常退出的
  • WEXITSTATUS(status)WIFEXITED返回非零值時,我們可以用這個巨集來提取子程序的返回值

wait處理第一個已終止的子程序,如果沒有,但有至少一個子程序仍在執行,則阻塞等待到有一個子程序終止為止。
waitpid除了與wait相同的部分外,可以用PID指定子程序ID。PID有以下取值方式:

  • pid>0時,只等待程序ID等於pid的子程序,不管其它已經有多少子程序執行結束退出了,只要指定的子程序還沒有結束,waitpid就會一直等下去。

  • pid=-1時,等待任何一個子程序退出,沒有任何限制,此時waitpid和wait的作用一模一樣。

  • pid=0時,等待同一個程序組中的任何子程序,如果子程序已經加入了別的程序組,waitpid不會對它做任何理睬。

  • pid<-1時,等待一個指定程序組中的任何子程序,這個程序組的ID等於pid的絕對值。

另外,options提供了一些額外的選項來控制waitpid,目前在Linux中只支援WNOHANGWUNTRACED兩個選項,這是兩個常數,可以用|運算子把它們連線起來使用。尤其是WNOHANG這個選項,可以避免wait方法因沒有完成的子程序而阻塞回收程序(一般是父程序呼叫)

返回值和錯誤
waitpid的返回值比wait稍微複雜一些,一共有3種情況:
1、當正常返回的時候,waitpid返回收集到的子程序的程序ID;
2、如果設定了選項WNOHANG,而呼叫中waitpid發現沒有已退出的子程序可收集,則返回0;
3、如果呼叫中出錯,則返回-1,這時errno會被設定成相應的值以指示錯誤所在;
PS 當pid所指示的子程序不存在,或此程序存在,但不是呼叫程序的子程序,waitpid就會出錯返回,這時errno被設定為ECHILD;

SIGPIPE訊號

在客戶端與伺服器建立連線後,如果伺服器單方面主動關閉連線(比如終止程序),這時伺服器會對客戶端傳送一個FIN,連線進入半關閉狀態(兩次握手)。這時客戶端仍可以向該連線的套接字中寫入資料(這時允許的)。當伺服器接收到來自客戶的資料時,如果伺服器開啟套接字的程序已經終止(不可能繼續接受資料了),於是相應一個RST訊號。要是客戶端不理會這個RST,繼續寫入資料時。也就是說當一個程序向某個已收到RST的套接字執行寫操作時,核心向該程序傳送一個SIGPIPE訊號,訊號預設行為是終止程序。另外,無論怎麼處理該訊號,寫操作都會返回一個EPIPE錯誤

如何在第一次寫操作時而不是第二次寫操作時捕獲該訊號?這是不可能的。第一次寫操作引發RST,第二次寫引發SIGPIPE。寫一個已接受FIN的套接字不成問題,但寫一個接受了RST的套接字則是一個錯誤。

相關推薦

作業總結1

收到網易的入職前作業,感覺都費勁(捂臉)。學習之餘做點筆記吧。 這部分主要涉及伺服器端的作業:用Python完成一個聊天視窗,以及若干附加的功能。 在看python文件時候注意到了兩個地址簇或者叫介面(因為直接影響了通訊協議):AF_INET和AF_UNIX

作業總結3.0Windows程式開發

看DirectX書的的時候,發現示例程式碼給出的部分與以往的主函式int main(int argc, char **argv)不同,以為只是給了個函式,主函式得自己寫。查閱了資料後發現是孤陋寡聞,原來windows應用程式的入口函式定義本來就比較特別。

ajax技術整理總結1

col () stat sta pre resp tel html func 1.創建ajax對象 var xhr=new XMLHttpRequest(); 4.監聽狀態信息 xhr.onreadystatechange=function(){ //4接收完畢

log4net 使用總結- 1在ASP.NET MVC 中使用

站點 href 還需 配置文件 str nag org src stat 1. 去官網下載log4net.dll,增加引用到站點下(你也可以通過nuget 安裝) http://logging.apache.org/log4net/download_log4net.cgi

MEF學習總結1---總體架構

attr 總結 技術分享 dir target get gre round 管理 用了很久的MEF框架來做依賴註入,最近想把它的原理和機構總結一下,主要包括如下幾個方面: 1. 總體架構 2. .Net Composition Primitive 3. Attribu

總結1--- 數據庫

優點 分層 數據結構 存儲引擎 nsis tree 備份 可擴展 根節點 一、mysql 數據庫存儲的原理 存儲過程中是一個可編程的函數,它在數據庫中創建並保存。 它可以有SQL語句和一些特殊的控制結構組成。當希望在不同的應用程序或平臺上執行相同的函數,或者封裝特定功能

八大排序算法總結1

n-1 冒泡排序 int 排序算法 length != 位置 倒數 選擇 冒泡排序: 第一輪:從下標0到n-1(n 是數組長度),如果前一個元素比後一個元素大,那麽,相鄰的兩兩交換,最後數組中最大的元素放在最後一個位置上。 第二輪:從標0到n-2,重復上過程,這樣第二大的元

Linux查看日誌方法總結1

關鍵字 http grep 定時 abd cab 我們 做的 ext 註:日誌文件為:test.log 1.tail -f test.log 查看當前打印的日誌(平時就知道這方法!打印出的長度有限制。) 以下為網上搜集的: 2.先必須了解兩個最基本的命令: tai

Python筆記總結1

Language 界面 關系運算符 unp expect ber integer file back 一、變量在python中不需要為變量制定數據類型。可以單行定義多個變量。>>> a, b = 2, 3.4 >>> a 2 >&g

golong基礎知識總結1

import 調用 一個 需要 文件中 一個數 col 遍歷 print go語言結構   go語言的基礎組成:包聲明,引入包,函數,變量,語句和表達式,註釋   包聲明:一個文件夾下只能聲明一個包,否則就會報錯(即同一個文件夾下,可以有多個go文件,但這些文件聲明的包的名

leetcode刷題總結1

solution 遍歷 AC 復雜度 刷題 may example AR 記錄 1、Two Sum Given an array of integers, return indices of the two numbers such that they add up to

Hadoop架構的初略總結1

安全 use 請求 參考 內存 文件系統 href 獲得 監控 Hadoop架構的初略總結(1) Hadoop是一個開源的分布式系統基礎架構,此架構可以幫助用戶可以在不了解分布式底層細節的情況下開發分布式程序。 首先我們要理清楚幾個問題。 1.我們為什麽需要Hadoop

Spring-Batch學習總結1——重要概念,環境搭建,名詞解釋,第一個項目及異常處理

img truct 設定 uil sna sta col key services Spring-batch框架學習總結(1)一.初識Spring-batch框架:1.核心名詞解釋:Job:是Spring-batch框架的核心概念,它包含了批處理的所有操作Step:每一個J

phthon學習總結1

pytho 保留字 大小寫 特殊字符 int 開頭 字母數 操作 定義 1、print("hello word") 2、變量、常量:   變量是存儲信息、方便調用、修改操作   常量固定不變的量,python用字母大寫區分。無常量。 命名規則: 1)字母數字下劃線組成。 2

Redis學習總結1——Redis記憶體資料庫詳細教程

1.Redis是什麼 2.redis的作者何許人也 3.誰在使用redis 4.學會安裝redis 5.學會啟動redis 6.使用redis客戶端 7.redis資料結構 – 簡介 8.redis資料結構 – strings 9.redis資料結構 – lists 10.redis

設計模式總結1

設計模式總結(1) 單例模式 單例模式是java設計模式中較為簡單但使用廣泛的一種建立型模式。使用這種設計模式的類不需要例項化,可以直接使用並且只能有一個自己建立的例項。這樣的優點是在一個類如果需要被頻繁使用的場景下可以減少記憶體開銷。 單例模式有多種實現方法: 餓漢式

spark知識點總結1

1.RDD彈性分散式資料集:是抽象出來的概念,元素的集合。是一批節點上一批資料的集合。 分散式:每個rdd會把資料分成多個parttioner放在多個節點上。eg:90萬條資料放在9個節點上面,每個   節點9萬條資料。 彈性:eg:每個節點上面個的記憶體中只能存放5萬條資料,那麼

作業練習1

1.在server主機中配置yum倉庫,並安裝gcc編譯器 (1)從真機上下載rhel-server-7.0-x86_64-dvd.iso到虛擬機器 (2)掛載:mount rhel-server-7.0-x86_64-dvd.iso /mnt (3)rm -rf /etc/yum.

c語言程式設計常見問題總結1

總結1: 將全域性變數放在會被多次呼叫的標頭檔案中,編譯會報錯:該變數被多次定義,所以是最好把全域性變數放在.c檔案中。 總結2:  Getche()函式,輸入後立即從控制檯取字元,不以回車為結束(帶回顯); Getch()是一個不回顯函式,當用戶按下某個字元時,函式自動讀

事務學習總結1——事務的基本概念

一:什麼是事務?     對資料庫讀寫一系列操作的合集。     具有"ACID"的特性,即原子性、一致性、隔離性、永續性。     核心點是鎖與併發。 二:主要用在哪些場景?解決了什麼問題?