0. Internet和HTTP協(xié)議以及Apache多路處理模塊工作原理

1. Internet和HTTP協(xié)議

1.1 Internet 因特網(wǎng)

因特網(wǎng)是"Internet”的中文譯名,它起源于美國的五角大樓,它的前身是美國國防部高級(jí)研究計(jì)劃局(ARPA)主持研制的ARPAnet。20世紀(jì)50年代末,正處于冷戰(zhàn)時(shí)期。當(dāng)時(shí)美國軍方為了自己的計(jì)算機(jī)網(wǎng)絡(luò)在受到襲擊時(shí),即使部分網(wǎng)絡(luò)被摧毀,其余部分仍能保持通信聯(lián)系,便由美國國防部的高級(jí)研究計(jì)劃局(ARPA)建設(shè)了一個(gè)軍用網(wǎng),叫做"阿帕網(wǎng)”(ARPAnet)。阿帕網(wǎng)于1969年正式啟用,當(dāng)時(shí)僅連接了4臺(tái)計(jì)算機(jī),供科學(xué)家們進(jìn)行計(jì)算機(jī)聯(lián)網(wǎng)實(shí)驗(yàn)用,這就是因特網(wǎng)的前身。

到70年代,ARPAnet已經(jīng)有了好幾十個(gè)計(jì)算機(jī)網(wǎng)絡(luò),但是每個(gè)網(wǎng)絡(luò)只能在網(wǎng)絡(luò)內(nèi)部的計(jì)算機(jī)之間互聯(lián)通信,不同計(jì)算機(jī)網(wǎng)絡(luò)之間仍然不能互通。為此, ARPA又設(shè)立了新的研究項(xiàng)目,支持學(xué)術(shù)界和工業(yè)界進(jìn)行有關(guān)的研究,研究的主要內(nèi)容就是想用一種新的方法將不同的計(jì)算機(jī)局域網(wǎng)互聯(lián),形成"互聯(lián)網(wǎng)”。研究人員稱之為"internetwork”,簡稱"Internet"。

在研究實(shí)現(xiàn)互聯(lián)的過程中,計(jì)算機(jī)軟件起了主要的作用。1974年,出現(xiàn)了連接分組網(wǎng)絡(luò)的協(xié)議,其中就包括了TCP/IP協(xié)議。TCP/IP有一個(gè)非常重要的特點(diǎn),就是開放性,即TCP/IP的規(guī)范和Internet的技術(shù)都是公開的。目的就是使任何廠家生產(chǎn)的計(jì)算機(jī)都能相互通信,使Internet成為一個(gè)開放的系統(tǒng),這正是后來Internet得到飛速發(fā)展的重要原因。ARPA在1982年接受了TCP/IP,選定Internet為主要的計(jì)算機(jī)通信系統(tǒng),并把其它的軍用計(jì)算機(jī)網(wǎng)絡(luò)都轉(zhuǎn)換到TCP/IP。1983年,ARPAnet分成兩部分:一部分軍用,稱為MILNET;另一部分仍稱ARPAnet,供民用。

1986年,美國國家科學(xué)基金組織(NSF)將分布在美國各地的5個(gè)為科研教育服務(wù)的超級(jí)計(jì)算機(jī)中心互聯(lián),并支持地區(qū)網(wǎng)絡(luò),形成SNSFnet。1988 年,SNSFnet替代ARPAnet成為Internet的主干網(wǎng)。NSFnet主干網(wǎng)利用了在ARPAnet中已證明是非常成功的TCP/IP技術(shù),準(zhǔn)許各大學(xué)、政府或私人科研機(jī)構(gòu)的網(wǎng)絡(luò)加入。1989年,ARPAnet解散,Internet從軍用轉(zhuǎn)向民用。

Internet的發(fā)展引起了商家的極大興趣。1992年,美國IBM、MCI、MERIT三家公司聯(lián)合組建了一個(gè)高級(jí)網(wǎng)絡(luò)服務(wù)公司(SNS),建立了一個(gè)新的網(wǎng)絡(luò),叫做SNSnet,成為Internet的另一個(gè)主干網(wǎng)。它與SNSFnet不同,NSFnet是由國家出資建立的,而SNSnet則是SNS 公司所有,從而使Internet開始走向商業(yè)化。

1995年4月30日,SNSFnet正式宣布停止運(yùn)作。而此時(shí)Internet的骨干網(wǎng)已經(jīng)覆蓋了全球91個(gè)國家,主機(jī)已超過400萬臺(tái)。而在當(dāng)前,因特網(wǎng)仍以驚人的速度向前發(fā)展。

在90年代,超文本標(biāo)識(shí)語言(HTML),即一個(gè)可以獲得因特網(wǎng)的圖像信息的超文本因特網(wǎng)協(xié)議被采用,使每一個(gè)人可以產(chǎn)生自己的圖像頁面(網(wǎng)址),然后成為一個(gè)巨大的虛擬超文本網(wǎng)絡(luò)的組成部分。

這個(gè)增強(qiáng)型的因特網(wǎng)又被非正式地稱為萬維網(wǎng),與此同時(shí)產(chǎn)生了數(shù)量龐大的新用戶群。于是,許多人用"因特網(wǎng)” 一詞指這個(gè)網(wǎng)絡(luò)的物理結(jié)構(gòu),包括連接所有事物的客戶機(jī)、服務(wù)器和網(wǎng)絡(luò);而用"萬維網(wǎng)”一詞指利用這個(gè)網(wǎng)絡(luò)可以訪問的所有網(wǎng)站和信息。

1.2 Internet和中國

北京時(shí)間1987年9月14日,錢天白建立起一個(gè)網(wǎng)絡(luò)節(jié)點(diǎn),通過電話撥號(hào)連接到國際互聯(lián)網(wǎng),向他的德國
朋友發(fā)出來自中國的第一封電子郵件:Across the Great Wall we can reach every corner in the world,自此,中國與國際計(jì)算機(jī)網(wǎng)絡(luò)開始連接在一起

中國互聯(lián)網(wǎng)連接世界:

1885年臺(tái)灣建省,首任巡撫劉銘傳派人與福州船政聯(lián)系,使用船政電報(bào)學(xué)堂畢業(yè)生為技術(shù)人員,于1887年鋪設(shè)成功臺(tái)灣淡水至福州川石海底電纜,全長117海里。這是我國自行設(shè)計(jì)安裝的第一條海底電纜。此電纜毀于第二次世界大戰(zhàn)

我國于1989年開始投入到全球海底光纜的投資與建設(shè)中來,并于1993年實(shí)現(xiàn)了首條國際海底光纜的登陸(中日之間C-J海底光纜系統(tǒng));隨后在1997年,我國參與建設(shè)的全球海底光纜系統(tǒng)(FLAG)建成并投入運(yùn)營,這也是第一條在我國登陸的洲際海底光纜中國連接世界目前共有8條光纜,四個(gè)登陸站允許入境,目前我國的登陸站設(shè)立在三個(gè)城市的四個(gè)地區(qū),分別是山東青島登陸站(隸屬中國聯(lián)通)、上海崇明登陸站(隸屬中國電信)、上海南匯登陸站(隸屬中國聯(lián)通)和廣東汕頭登陸站(隸屬中國電信)

1.3 跨網(wǎng)絡(luò)的主機(jī)間通訊

Socket套接字

image.png

套接字Socket, 是進(jìn)程間通信IPC的一種實(shí)現(xiàn),允許位于不同主機(jī)(或同一主機(jī))上不同進(jìn)程之間進(jìn)行通信和數(shù)據(jù)交換,SocketAPI出現(xiàn)于1983年,4.2 BSD實(shí)現(xiàn)

在建立通信連接的每一端,進(jìn)程間的傳輸要有兩個(gè)標(biāo)志:IP地址和端口號(hào),合稱為套接字地址 socket address

客戶機(jī)套接字地址定義了一個(gè)唯一的客戶進(jìn)程
服務(wù)器套接字地址定義了一個(gè)唯一的服務(wù)器進(jìn)程

image.png

Socket API: 封裝了內(nèi)核中所提供的socket通信相關(guān)的系統(tǒng)調(diào)用

Socket Domain: 根據(jù)其所使用的地址

  • AF_INET:Address Family,IPv4
  • AF_INET6:IPv6
  • AF_UNIX:同一主機(jī)上不同進(jìn)程之間通信時(shí)使用

Socket Type: 根據(jù)使用的傳輸層協(xié)議

  • SOCK_STREAM:流,tcp套接字,可靠地傳遞、面向連接
  • SOCK_DGRAM:數(shù)據(jù)報(bào),udp套接字,不可靠地傳遞、無連接
  • SOCK_RAW: 裸套接字,無須tcp或udp,APP直接通過IP包通信

客戶/服務(wù)器程序的套接字函數(shù)

image.png

套接字相關(guān)的系統(tǒng)調(diào)用:

  • socket() 創(chuàng)建一個(gè)套接字
  • bind() 綁定IP和端口
  • listen() 監(jiān)聽
  • accept() 接收請求
  • connect() 請求連接建立
  • write() 發(fā)送
  • read() 接收
  • close() 關(guān)閉連接

服務(wù)端會(huì)有兩個(gè)socket, 一個(gè)用于監(jiān)聽, 一個(gè)用于處理請求

Step 1: TCP 服務(wù)器創(chuàng)建socket
Step 2: (bind函數(shù))綁定協(xié)議, IPv4和端口號(hào)
Step 3: 讓socket監(jiān)聽在綁定的協(xié)議, IPv4和端口號(hào)上, 等待用戶連接
Step 4: 客戶端創(chuàng)建socket
Step 5: 通過connect函數(shù), 連接到服務(wù)器端socket
Step 6: 服務(wù)器端socket通過accept函數(shù)進(jìn)行接收, 此時(shí), 服務(wù)器端會(huì)生成一個(gè)新的New Socket專門用來處理這個(gè)客戶端請求, 原本的socket會(huì)繼續(xù)進(jìn)行監(jiān)聽, 等待客戶端連接

范例: nc程序模擬socket通信過程

# 實(shí)現(xiàn)服務(wù)端, 監(jiān)聽在10.0.0.81:8000

[12:40:36 root@CentOS-8-1 ~]#nc -l 8000

[12:41:38 root@CentOS-8-1 ~]#ss -ntl
State                       Recv-Q                      Send-Q                                             Local Address:Port                                             Peer Address:Port                      
LISTEN                      0                           128                                                      0.0.0.0:22                                                    0.0.0.0:*                         
LISTEN                      0                           1                                                        0.0.0.0:8000(監(jiān)聽在8000端口)                                    0.0.0.0:*                         
LISTEN                      0                           128                                                         [::]:22                                                       [::]:*                         
# 實(shí)現(xiàn)客戶端連接服務(wù)端10.0.0.81:8000

[12:40:35 root@centos-7-1 ~]#nc 10.0.0.81 8000

# 客戶端10.0.0.237向服務(wù)端10.0.0.81發(fā)送消息

[12:40:35 root@centos-7-1 ~]#nc 10.0.0.81 8000
i am 10.0.0.237 

# 服務(wù)端10.0.0.81向客戶端10.0.0.237發(fā)送信息

[12:40:31 root@CentOS-8-1 ~]#clear
[12:40:36 root@CentOS-8-1 ~]#nc -l 8000
i am 10.0.0.237
i am 10.0.0.81

# 客戶端接收到服務(wù)端消息

[12:40:35 root@centos-7-1 ~]#nc 10.0.0.81 8000
i am 10.0.0.237 
i am 10.0.0.81

# 服務(wù)端接收到10.0.0.237客戶端發(fā)來的消息

[12:20:00 root@CentOS-8-1 ~]#nc -l 8000
i am 10.0.0.237

# nc只是一個(gè)簡單的網(wǎng)絡(luò)連接程序, 一旦接收到一個(gè)客戶端連接, 就會(huì)把當(dāng)前的監(jiān)聽(Listen)連接轉(zhuǎn)為ESTAB而不是重新創(chuàng)建一個(gè)連接

范例: 通過strace命令查看socket實(shí)現(xiàn)的過程

# 服務(wù)端創(chuàng)建socket

[12:23:05 root@CentOS-8-1 ~]#strace -ff -o nc.log nc -l 8000

# 客戶端連接到服務(wù)端

[12:22:32 root@centos-7-1 ~]#nc 10.0.0.81 8000

一個(gè)socket連接包含五個(gè)元素, 任何一個(gè)元素改變, 都會(huì)成為一個(gè)新的連接

源ip
源端口號(hào)
目標(biāo)ip
目標(biāo)端口號(hào)
協(xié)議類型
[12:24:26 root@CentOS-8-1 ~]#cat nc.log.22767 
execve("/usr/bin/nc", ["nc", "-l", "8000"], 0x7ffeb275c6d8 /* 22 vars */) = 0
brk(NULL)                               = 0x5568b6743000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffe3db6a90) = -1 EINVAL (Invalid argument)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=24073, ...}) = 0
mmap(NULL, 24073, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f81d1f54000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libbsd.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`G\0\0\0\0\0\0"..., 832) = 832
lseek(3, 89336, SEEK_SET)               = 89336
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
fstat(3, {st_mode=S_IFREG|0755, st_size=120128, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f81d1f52000
lseek(3, 89336, SEEK_SET)               = 89336
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 2195792, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d1b19000
mprotect(0x7f81d1b2f000, 2097152, PROT_NONE) = 0
mmap(0x7f81d1d2f000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16000) = 0x7f81d1d2f000
mmap(0x7f81d1d31000, 336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f81d1d31000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p<\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=142528, ...}) = 0
mmap(NULL, 2189952, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d1902000
mprotect(0x7f81d1916000, 2093056, PROT_NONE) = 0
mmap(0x7f81d1b15000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13000) = 0x7f81d1b15000
mmap(0x7f81d1b17000, 6784, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f81d1b17000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libtls.so.25", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340s\0\0\0\0\0\0"..., 832) = 832
lseek(3, 76560, SEEK_SET)               = 76560
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
fstat(3, {st_mode=S_IFREG|0755, st_size=87360, ...}) = 0
lseek(3, 76560, SEEK_SET)               = 76560
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 2179384, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d16ed000
mprotect(0x7f81d1700000, 2097152, PROT_NONE) = 0
mmap(0x7f81d1900000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x13000) = 0x7f81d1900000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\2607\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=4176104, ...}) = 0
mmap(NULL, 3938144, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d132b000
mprotect(0x7f81d14e4000, 2093056, PROT_NONE) = 0
mmap(0x7f81d16e3000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b8000) = 0x7f81d16e3000
mmap(0x7f81d16e9000, 14176, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f81d16e9000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/librt.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340%\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=98680, ...}) = 0
mmap(NULL, 2132928, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d1122000
mprotect(0x7f81d1129000, 2097152, PROT_NONE) = 0
mmap(0x7f81d1329000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x7000) = 0x7f81d1329000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libssl.so.1.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\373\1\0\0\0\0\0"..., 832) = 832
lseek(3, 547192, SEEK_SET)              = 547192
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
fstat(3, {st_mode=S_IFREG|0755, st_size=615504, ...}) = 0
lseek(3, 547192, SEEK_SET)              = 547192
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 2699312, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d0e8e000
mprotect(0x7f81d0f14000, 2097152, PROT_NONE) = 0
mmap(0x7f81d1114000, 53248, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x86000) = 0x7f81d1114000
mmap(0x7f81d1121000, 48, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f81d1121000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libcrypto.so.1.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\260\7\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=3058736, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f81d1f50000
mmap(NULL, 5123968, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d09ab000
mprotect(0x7f81d0c5b000, 2097152, PROT_NONE) = 0
mmap(0x7f81d0e5b000, 192512, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2b0000) = 0x7f81d0e5b000
mmap(0x7f81d0e8a000, 16256, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f81d0e8a000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libpthread.so.0", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000o\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=470312, ...}) = 0
mmap(NULL, 2225344, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d078b000
mprotect(0x7f81d07a6000, 2093056, PROT_NONE) = 0
mmap(0x7f81d09a5000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a000) = 0x7f81d09a5000
mmap(0x7f81d09a7000, 13504, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f81d09a7000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libz.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0'\0\0\0\0\0\0"..., 832) = 832
lseek(3, 88568, SEEK_SET)               = 88568
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
fstat(3, {st_mode=S_IFREG|0755, st_size=95232, ...}) = 0
lseek(3, 88568, SEEK_SET)               = 88568
read(3, "\4\0\0\0\20\0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0", 32) = 32
mmap(NULL, 2187272, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d0574000
mprotect(0x7f81d058a000, 2093056, PROT_NONE) = 0
mmap(0x7f81d0789000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x15000) = 0x7f81d0789000
mmap(0x7f81d078a000, 8, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f81d078a000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220\20\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=36824, ...}) = 0
mmap(NULL, 2109744, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f81d0370000
mprotect(0x7f81d0373000, 2093056, PROT_NONE) = 0
mmap(0x7f81d0572000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x2000) = 0x7f81d0572000
close(3)                                = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f81d1f4e000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f81d1f4c000
arch_prctl(ARCH_SET_FS, 0x7f81d1f4f600) = 0
mprotect(0x7f81d16e3000, 16384, PROT_READ) = 0
mprotect(0x7f81d0572000, 4096, PROT_READ) = 0
mprotect(0x7f81d0789000, 4096, PROT_READ) = 0
mprotect(0x7f81d09a5000, 4096, PROT_READ) = 0
mprotect(0x7f81d0e5b000, 176128, PROT_READ) = 0
mprotect(0x7f81d1114000, 36864, PROT_READ) = 0
mprotect(0x7f81d1329000, 4096, PROT_READ) = 0
mprotect(0x7f81d1900000, 4096, PROT_READ) = 0
mprotect(0x7f81d1b15000, 4096, PROT_READ) = 0
mprotect(0x7f81d1d2f000, 4096, PROT_READ) = 0
mprotect(0x5568b5aa8000, 4096, PROT_READ) = 0
mprotect(0x7f81d1f5a000, 4096, PROT_READ) = 0
munmap(0x7f81d1f54000, 24073)           = 0
set_tid_address(0x7f81d1f4f8d0)         = 22767
set_robust_list(0x7f81d1f4f8e0, 24)     = 0
rt_sigaction(SIGRTMIN, {sa_handler=0x7f81d07919a0, sa_mask=[], sa_flags=SA_RESTORER|SA_SIGINFO, sa_restorer=0x7f81d079ddd0}, NULL, 8) = 0
rt_sigaction(SIGRT_1, {sa_handler=0x7f81d0791a30, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART|SA_SIGINFO, sa_restorer=0x7f81d079ddd0}, NULL, 8) = 0
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
access("/etc/system-fips", F_OK)        = -1 ENOENT (No such file or directory)
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f81d1362790}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
brk(NULL)                               = 0x5568b6743000
brk(0x5568b6764000)                     = 0x5568b6764000
brk(NULL)                               = 0x5568b6764000
socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(3, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
bind(3, {sa_family=AF_INET, sin_port=htons(8000), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 1)                            = 0
accept4(3, {sa_family=AF_INET, sin_port=htons(43684), sin_addr=inet_addr("10.0.0.237")}, [128 => 16], SOCK_NONBLOCK) = 4
poll([{fd=0, events=POLLIN}, {fd=4, events=0}, {fd=4, events=POLLIN}, {fd=1, events=0}], 4, -1

范例: socket 相關(guān)系統(tǒng)調(diào)用

[root@centos8 ~]#dnf -y install man-pages
[root@centos8 ~]#man 2 socket
[root@centos8 ~]#man 2 bind
[root@centos8 ~]#man 2 listen
[root@centos8 ~]#man 2 accept
[root@centos8 ~]#man 2 read
[root@centos8 ~]#man 2 write
[root@centos8 ~]#man 2 connect
[root@centos8 ~]#man 2 close

1.4 HTTP 超文本傳輸協(xié)議

1.4.1 HTTP相關(guān)概念

互聯(lián)網(wǎng):是網(wǎng)絡(luò)的網(wǎng)絡(luò),是所有類型網(wǎng)絡(luò)的母集。
因特網(wǎng):世界上最大的互聯(lián)網(wǎng)網(wǎng)絡(luò)。即因特網(wǎng)概念從屬于互聯(lián)網(wǎng)概念。習(xí)慣上,大家把連接在因特網(wǎng)上的計(jì)算機(jī)都成為主機(jī)。
萬維網(wǎng):WWW(world wide web)萬維網(wǎng)并非某種特殊的計(jì)算機(jī)網(wǎng)絡(luò),是一個(gè)大規(guī)模的、聯(lián)機(jī)式的信息貯藏所,使用鏈接的方法能非常方便地從因特網(wǎng)上的一個(gè)站點(diǎn)訪問另一個(gè)站點(diǎn)(超鏈技術(shù)),具有提供分布式服務(wù)的特點(diǎn)。萬維網(wǎng)是一個(gè)分布式的超媒體系統(tǒng),是超文本系統(tǒng)的擴(kuò)充,基于B/S架構(gòu)實(shí)現(xiàn)

image.png

URL:萬維網(wǎng)使用統(tǒng)一資源定位符(Uniform Resource Locator)來標(biāo)志萬維網(wǎng)上的各種文檔,并使每個(gè)文檔在整個(gè)因特網(wǎng)的范圍內(nèi)具有唯一的標(biāo)識(shí)符URL。

HTTP:為解決"用什么樣的網(wǎng)絡(luò)協(xié)議來實(shí)現(xiàn)整個(gè)因特網(wǎng)上的萬維網(wǎng)文檔”這一難題,就要使萬維網(wǎng)客戶程序(以瀏覽器為主,但不限于瀏覽器)與萬維網(wǎng)服務(wù)器程序之間的交互遵守嚴(yán)格的協(xié)議,即超文本傳送協(xié)議(HyperText Transfer Protocol)。HTTP是處于應(yīng)用層的協(xié)議,使用TCP傳輸層協(xié)議進(jìn)行可靠的傳送。因此,需要特別提醒的是,萬維網(wǎng)是基于因特網(wǎng)的一種廣泛因特網(wǎng)應(yīng)用系統(tǒng),且萬維網(wǎng)采用的是HTTP(80/TCP)和 HTTPS(443/TCP)的傳輸協(xié)議,但因特網(wǎng)還有其他的網(wǎng)絡(luò)應(yīng)用系統(tǒng)(如:FTP、SMTP等等)。

HTML:為了解決"怎樣使不同作者創(chuàng)作的不同風(fēng)格的萬維網(wǎng)文檔,都能在因特網(wǎng)上的各種主機(jī)上顯示出來,同時(shí)使用戶清楚地知道在什么地方存在著鏈接”這一問題,萬維網(wǎng)使用超文本標(biāo)記語言(HyperText Markup Language),使得萬維網(wǎng)頁面的設(shè)計(jì)者可以很方便地用鏈接從頁面的某處鏈接到因特網(wǎng)的任何一個(gè)萬維網(wǎng)頁面,并且能夠在自己的主機(jī)品目上將這些頁面顯示出來。HTML與txt一樣,僅僅是是一種文檔,不同之處在于,這種文檔專供于瀏覽器上為瀏覽器用戶提供統(tǒng)一的界面呈現(xiàn)的統(tǒng)一規(guī)約。且具備結(jié)構(gòu)化的特征,這是txt所不具備的強(qiáng)制規(guī)定。

HTTP協(xié)議規(guī)定了主機(jī)之間交換文件的規(guī)則, 而HTML規(guī)定了文件的格式

1.4.2 瀏覽器訪問網(wǎng)站的過程

image.png

1.4.3 HTTP協(xié)議通信過程

HTTP(HyperText Transfer Protocol,超文本傳輸協(xié)議)是一種用于分布式、協(xié)作式和超媒體信息系統(tǒng)的應(yīng)用層協(xié)議。HTTP是萬維網(wǎng)的數(shù)據(jù)通信的基礎(chǔ)設(shè)計(jì)。HTTP最初的目的是為了提供一種遠(yuǎn)距離共享知識(shí)的方式,借助多文檔進(jìn)行關(guān)聯(lián)實(shí)現(xiàn)超文本,連成相互參閱的WWW(world wide web,萬維網(wǎng))。

HTTP的發(fā)展是由蒂姆·伯納斯-李(Tim Berners-Lee)于1989年在歐洲核子研究組織(CERN)所發(fā)起。HTTP的標(biāo)準(zhǔn)制定由萬維網(wǎng)協(xié)會(huì)(World Wide Web Consortium,W3C)和互聯(lián)網(wǎng)工程任務(wù)組(Internet Engineering Task Force,IETF)進(jìn)行協(xié)調(diào),最終發(fā)布了一系列的RFC,其中最著名的是1999年6月公布的 RFC 2616,定義了HTTP協(xié)議中現(xiàn)今廣泛使用的一個(gè)版本——HTTP 1.1版。

HTTP服務(wù)通信過程

image.png

HTTP協(xié)議分層

image.png

1.4.4 HTTP相關(guān)技術(shù)

1.4.4.1 web開發(fā)語言

HTTP: Hyper Text Transfer Protocol 應(yīng)用層協(xié)議,默認(rèn)端口: 80/tcp

WEB前端開發(fā)語言:

  • html: Hyper Text Markup Language 超文本標(biāo)記語言,編程語言,主要負(fù)責(zé)實(shí)現(xiàn)頁面的結(jié)構(gòu)。
  • css: Cascading Style Sheet 層疊樣式表, 定義了如何顯示(裝扮) HTML 元素,比如:字體大小和顏色屬性等。樣式通常保存在外部的 .css 文件中。通過僅編輯一個(gè)簡單的 CSS 文檔,可以同時(shí)改變站點(diǎn)中所有頁面的布局和外觀。
  • javascript: 實(shí)現(xiàn)網(wǎng)頁的動(dòng)畫效果,但實(shí)屬于靜態(tài)資源。

靜態(tài)頁面vs動(dòng)態(tài)頁面:

  • 靜態(tài)頁面: 點(diǎn)擊查看網(wǎng)頁源代碼后顯示的代碼和服務(wù)器存放的頁面代碼相同
  • 動(dòng)態(tài)頁面: 點(diǎn)擊查看網(wǎng)頁源代碼后顯示的代碼和服務(wù)器存放的頁面代碼不同, 動(dòng)態(tài)頁面在瀏覽器查看網(wǎng)頁源代碼看到的是程序代碼在后端執(zhí)行后的結(jié)果, 而非程序代碼本身

1.4.4.2 MIME

MIME : Multipurpose Internet Mail Extensions 多用途互聯(lián)網(wǎng)郵件擴(kuò)展
文件 /etc/mime.types ,來自于mailcap包. 該文件定義了本地web服務(wù)器能接收哪種類型的文件通過HTTP協(xié)議傳輸
MIME格式:major/minor

早期的HTTP協(xié)議只能在網(wǎng)絡(luò)中傳遞文字頁面, 通過MIME技術(shù), 實(shí)現(xiàn)在網(wǎng)絡(luò)中傳輸其他類型的文件, 比如圖片, 視頻等。

MIME最早是應(yīng)用在郵件技術(shù), 后來被HTTP利用解決在網(wǎng)絡(luò)中傳輸不同類型的文件。

參考鏈接:
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_Types
http://www.w3school.com.cn/media/media_mimeref.asp

范例:

text/plain   # 純文字文本
text/html  
text/css 
image/jpeg 
image/png 
video/mp4 
application/javascript 
application/json
...

1.4.4.3 URI, URL和URN

URI: Uniform Resource Identifier 統(tǒng)一資源標(biāo)識(shí),分為URL 和 URN

URN:Uniform Resource Naming,統(tǒng)一資源命名, 只是用來描述一個(gè)互聯(lián)網(wǎng)資源的名稱

  • 示例: P2P下載使用的磁力鏈接是URN的一種實(shí)現(xiàn)
    magnet:?xt=urn:btih:660557A6890EF888666

URL:Uniform Resorce Locator,統(tǒng)一資源定位符,用于描述某服務(wù)器某特定資源位置, 也就是完整的網(wǎng)址路徑

兩者區(qū)別:URN如同一個(gè)人的名稱,而URL代表一個(gè)人的住址。換言之,URN定義某事物的身份,而URL提供查找該事物的方法。URN僅用于命名,而不指定地址

URL組成:

image.png
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
scheme:方案,訪問服務(wù)器以獲取資源時(shí)要使用哪種協(xié)議
user:用戶,某些方案訪問資源時(shí)需要的用戶名
password:密碼,用戶對(duì)應(yīng)的密碼,中間用:分隔
Host:主機(jī),資源宿主服務(wù)器的主機(jī)名或IP地址
port:端口,資源宿主服務(wù)器正在監(jiān)聽的端口號(hào),很多方案有默認(rèn)端口號(hào)
path:路徑,服務(wù)器資源的本地名,由一個(gè)/將其與前面的URL組件分隔
params:參數(shù),指定輸入的參數(shù),參數(shù)為名/值對(duì),多個(gè)參數(shù),用;分隔
query:查詢,傳遞參數(shù)給程序,如數(shù)據(jù)庫,用?分隔,多個(gè)查詢用&分隔
frag:片段,一小片或一部分資源的名字,此組件在客戶端使用,用#分隔

URL示例:

http://www.it.com:8080/images/logo.jpg
ftp://admin:password@172.16.0.1/pub/linux.ppt
rtsp://videoserver/video_demo/ # Real Time Streaming Protocol
gcomm://10.0.0.8,10.0.0.18,10.0.0.28
http://www.it.com/bbs/hello;gender=f/send;type=title
https://list.jd.com(省略port:80端口號(hào))/list.html?cat=670,671,672&ev=14_2&sort=sort_totalsales15_desc&trans=1
http://apache.org/index.html#projects-list

1.4.4.4 統(tǒng)計(jì)網(wǎng)站訪問量

網(wǎng)站訪問量統(tǒng)計(jì)的重要指標(biāo):

  • IP(獨(dú)立IP):即Internet Protocol, 指獨(dú)立IP數(shù)。一天內(nèi)來自相同客戶機(jī)IP 地址只計(jì)算一次,記錄遠(yuǎn)程客戶機(jī)IP地址的計(jì)算機(jī)訪問網(wǎng)站的次數(shù),是衡量網(wǎng)站流量的重要指標(biāo)
  • PV(訪問量): 即Page View, 頁面瀏覽量或點(diǎn)擊量,用戶每次刷新即被計(jì)算一次,PV反映的是瀏覽某網(wǎng)站的頁面數(shù),PV與來訪者的數(shù)量成正比,PV并不是頁面的來訪者數(shù)量,而是網(wǎng)站被訪問的頁面數(shù)量
  • UV(獨(dú)立訪客):即Unique Visitor,訪問網(wǎng)站的一臺(tái)電腦為一個(gè)訪客。一天內(nèi)相同的客戶端只被計(jì)算一次??梢岳斫獬稍L問某網(wǎng)站的電腦的數(shù)量。網(wǎng)站判斷來訪電腦的身份是通過cookies實(shí)現(xiàn)的。如果更換了IP后但不清除cookies,再訪問相同網(wǎng)站,該網(wǎng)站的統(tǒng)計(jì)中UV數(shù)是不變的

1.4.5 HTTP工作機(jī)制

一次http事務(wù)包括:

  • http請求:http request
  • http響應(yīng):http response

Web資源:web resource, 一個(gè)網(wǎng)頁由多個(gè)資源(文件)構(gòu)成,打開一個(gè)頁面,通常會(huì)有多個(gè)資源展示出來,但是每個(gè)資源都要單獨(dú)請求。因此,一個(gè)Web 頁面通常并不是單個(gè)資源,而是一組資源的集合

資源類型:

  • 靜態(tài)文件:無需服務(wù)端做出額外處理
    文件后綴:.html, .txt, .jpg, .js, .css, .mp3, .avi
  • 動(dòng)態(tài)文件:服務(wù)端執(zhí)行程序,返回執(zhí)行的結(jié)果
    文件后綴:.php, .jsp ,.asp

HTTP連接請求:

image.png

串行連接和并行連接:

① 串行連接


image.png

② 并行連接


image.png

串行,持久連接和管道:

③ 持久連接

image.png

④ 管道化連接

image.png

提高HTTP連接性能, 加快網(wǎng)站資源的訪問:

  • 并行連接:通過多條TCP連接發(fā)起并發(fā)的HTTP請求
  • 持久連接:keep-alive,重用TCP連接,以消除連接和關(guān)閉的延遲, 以事務(wù)個(gè)數(shù)和時(shí)間來決定是否關(guān)閉連接
  • 管道化連接:通過共享TCP連接,發(fā)起并發(fā)的HTTP請求
  • 復(fù)用的連接:交替?zhèn)魉驼埱蠛晚憫?yīng)報(bào)文(實(shí)驗(yàn)階段)

1.4.6 HTTP 協(xié)議版本

image.png
  • http/0.9:

1991,原型版本,功能簡陋,只有一個(gè)命令GET。GET /index.html ,服務(wù)器只能回應(yīng)HTML格式字符串,不能回應(yīng)別的格式

  • http/1.0:

1996年5月, 支持cache, MIME, method

每個(gè)TCP連接只能發(fā)送一個(gè)請求,發(fā)送數(shù)據(jù)完畢,連接就關(guān)閉,如果還要請求其他資源,就必須再新建一個(gè)連接

引入了POST命令和HEAD命令
頭信息是 ASCII 碼,后面數(shù)據(jù)可為任何格式。服務(wù)器回應(yīng)時(shí)會(huì)告訴客戶端,數(shù)據(jù)是什么格式,即Content-Type字段的作用。這些數(shù)據(jù)類型總稱為MIME多用途互聯(lián)網(wǎng)郵件擴(kuò)展,每個(gè)值包括一級(jí)類型和二級(jí)類型,預(yù)定義的類型,也可自定義類型, 常見Content-Type值:text/xml image/jpeg audio/mp3

  • http/1.1:

1997年1月,引入了持久連接(persistent connection),即TCP連接默認(rèn)不關(guān)閉,可以被多個(gè)請求復(fù)用,不用聲明Connection: keep-alive。對(duì)于同一個(gè)域名,大多數(shù)瀏覽器允許同時(shí)建立6個(gè)持久連接引入了管道機(jī)制,即在同一個(gè)TCP連接里,客戶端可以同時(shí)發(fā)送多個(gè)請求,進(jìn)一步改進(jìn)了HTTP協(xié)議的效率。 一次三次握手, 可以完成多次資源的請求和相應(yīng)。

新增方法:PUT、PATCH、OPTIONS、DELETE

同一個(gè)TCP連接里,所有的數(shù)據(jù)通信是按次序進(jìn)行的。服務(wù)器只能順序處理回應(yīng),前面的回應(yīng)慢,會(huì)有許多請求排隊(duì),造成"隊(duì)頭堵塞"(Head-of-line blocking)

為避免上述問題,兩種方法:一是減少請求數(shù),二是同時(shí)多開持久連接。

網(wǎng)頁優(yōu)化技巧,如合并腳本和樣式表、將圖片嵌入CSS代碼、域名分片(domain sharding)等
HTTP 協(xié)議不帶有狀態(tài),每次請求都必須附上所有信息。請求的很多字段都是重復(fù)的,浪費(fèi)帶寬,影響速度

HTTP1.0和HTTP1.1的區(qū)別:

image.png

  • 緩存處理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires來做為緩存判斷的標(biāo)準(zhǔn),HTTP1.1則引入了更多的緩存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None?Match等更多可供選擇的緩存頭來控制緩存策略
  • 帶寬優(yōu)化及網(wǎng)絡(luò)連接的使用,HTTP1.0中,存在一些浪費(fèi)帶寬的現(xiàn)象,例如:客戶端只是需要某個(gè)對(duì)象的一部分,而服務(wù)器卻將整個(gè)對(duì)象送過來了,并且不支持?jǐn)帱c(diǎn)續(xù)傳功能,HTTP1.1則在請求頭引入了range頭域,它允許只請求資源的某個(gè)部分,即返回碼是206(Partial Content),方便了開發(fā)者自由的選擇以便于充分利用帶寬和連接
  • 錯(cuò)誤通知的管理,在HTTP1.1中新增24個(gè)狀態(tài)響應(yīng)碼,如409(Conflict)表示請求的資源與資源當(dāng)前狀態(tài)沖突;410(Gone)表示服務(wù)器上的某個(gè)資源被永久性的刪除
  • Host 頭處理,在HTTP1.0中認(rèn)為每臺(tái)服務(wù)器都綁定一個(gè)唯一的IP地址,因此,請求消息中的URL并沒有傳遞主機(jī)名(hostname)。但隨著虛擬主機(jī)技術(shù)的發(fā)展,在一臺(tái)物理服務(wù)器上可以存在多個(gè)虛擬主機(jī)(Multi-homed Web Servers),并且它們共享一個(gè)IP地址。HTTP1.1的請求消息和響應(yīng)消息都應(yīng)支持Host頭域,且請求消息中如果沒有Host頭域會(huì)報(bào)告一個(gè)錯(cuò)誤(400 Bad Request)
  • 長連接,HTTP 1.1支持長連接(PersistentConnection)和請求的流水線(Pipelining)處理,在一個(gè)TCP連接上可以傳送多個(gè)HTTP請求和響應(yīng),減少了建立和關(guān)閉連接的消耗和延遲,在
    HTTP1.1中默認(rèn)開啟Connection: keep-alive,彌補(bǔ)了HTTP1.0每次請求都要?jiǎng)?chuàng)建連接的缺點(diǎn)

HTTP1.0和1.1的問題:

  • HTTP1.x在傳輸數(shù)據(jù)時(shí),每次都需要重新建立連接,無疑增加了大量的延遲時(shí)間,特別是在移動(dòng)端更為突出
  • HTTP1.x在傳輸數(shù)據(jù)時(shí),所有傳輸?shù)膬?nèi)容都是明文,客戶端和服務(wù)器端都無法驗(yàn)證對(duì)方的身份,無法保證數(shù)據(jù)的安全性
  • HTTP1.x在使用時(shí),header里攜帶的內(nèi)容過大,增加了傳輸?shù)某杀?,并且每次請求header基本不怎么變化,尤其在移動(dòng)端增加用戶流量
  • 雖然HTTP1.x支持了keep-alive,來彌補(bǔ)多次創(chuàng)建連接產(chǎn)生的延遲,但是keep-alive使用多了同樣會(huì)給服務(wù)端帶來大量的性能壓力,并且對(duì)于單個(gè)文件被不斷請求的服務(wù)(例如圖片存放網(wǎng)站),
    keep-alive可能會(huì)極大的影響性能,因?yàn)樗谖募徽埱笾筮€保持了不必要的連接很長時(shí)間

HTTPS協(xié)議:

為解決安全問題,網(wǎng)景在1994年創(chuàng)建了HTTPS,并應(yīng)用在網(wǎng)景導(dǎo)航者瀏覽器中。 最初,HTTPS是與SSL一起使用的;在SSL逐漸演變到TLS時(shí)(其實(shí)兩個(gè)是一個(gè)東西,只是名字不同而已),最新的HTTPS也由在2000年五月公布的RFC 2818正式確定下來。HTTPS就是安全版的HTTP,目前大型網(wǎng)站基本實(shí)現(xiàn)全站HTTPS

HTTPS特點(diǎn):

  • HTTPS協(xié)議需要到CA申請證書,一般免費(fèi)證書很少,需要交費(fèi)
  • HTTP協(xié)議運(yùn)行在TCP之上,所有傳輸?shù)膬?nèi)容都是明文,HTTPS運(yùn)行在SSL/TLS之上,SSL/TLS運(yùn)行在TCP之上,所有傳輸?shù)膬?nèi)容都經(jīng)過加密的
  • HTTP和HTTPS使用的是不同的連接方式,端口不同,前者是80,后者是443
  • HTTPS可以有效的防止運(yùn)營商劫持,解決了防劫持的一個(gè)大問題
  • HTTPS 實(shí)現(xiàn)過程降低用戶訪問速度,但經(jīng)過合理優(yōu)化和部署,HTTPS 對(duì)速度的影響還是可以接受的

SPDY協(xié)議:

SPDY:2009年谷歌研發(fā),綜合HTTPS和HTTP兩者有點(diǎn)于一體的傳輸協(xié)議,主要特點(diǎn):

  • 降低延遲,針對(duì)HTTP高延遲的問題,SPDY優(yōu)雅的采取了多路復(fù)用(multiplexing)。多路復(fù)用通過多個(gè)請求stream共享一個(gè)tcp連接的方式,解決了HOL blocking的問題,降低了延遲同時(shí)提高了帶寬的利用率
  • 請求優(yōu)先級(jí)(request prioritization)。多路復(fù)用帶來一個(gè)新的問題是,在連接共享的基礎(chǔ)之上有可能會(huì)導(dǎo)致關(guān)鍵請求被阻塞。SPDY允許給每個(gè)request設(shè)置優(yōu)先級(jí),重要的請求就會(huì)優(yōu)先得到響應(yīng)。比如瀏覽器加載首頁,首頁的html內(nèi)容應(yīng)該優(yōu)先展示,之后才是各種靜態(tài)資源文件,腳本文件等加載,可以保證用戶能第一時(shí)間看到網(wǎng)頁內(nèi)容
  • header壓縮。HTTP1.x的header很多時(shí)候都是重復(fù)多余的。選擇合適的壓縮算法可以減小包的大小和數(shù)量
  • 基于HTTPS的加密協(xié)議傳輸,大大提高了傳輸數(shù)據(jù)的可靠性
  • 服務(wù)端推送(server push),采用了SPDY的網(wǎng)頁,例如網(wǎng)頁有一個(gè)sytle.css的請求,在客戶端收到sytle.css數(shù)據(jù)的同時(shí),服務(wù)端會(huì)將sytle.js的文件推送給客戶端,當(dāng)客戶端再次嘗試獲取sytle.js時(shí)就可以直接從緩存中獲取到,不用再發(fā)請求了

HTTP2協(xié)議:

http/2.0:2015年,HTTP2.0是SPDY的升級(jí)版

  • 頭信息和數(shù)據(jù)體都是二進(jìn)制,稱為頭信息幀和數(shù)據(jù)幀
  • 復(fù)用TCP連接,在一個(gè)連接里,客戶端和瀏覽器都可以同時(shí)發(fā)送多個(gè)請求或回應(yīng),且不用按順序一一對(duì)應(yīng),避免了"隊(duì)頭堵塞",此雙向的實(shí)時(shí)通信稱為多工(Multiplexing)
  • 引入頭信息壓縮機(jī)制(header compression),頭信息使用gzip或compress壓縮后再發(fā)送;客戶端和服務(wù)器同時(shí)維護(hù)一張頭信息表,所有字段都會(huì)存入這個(gè)表,生成一個(gè)索引號(hào),不發(fā)送同樣字段,只發(fā)送索引號(hào),提高速度
  • HTTP/2 允許服務(wù)器未經(jīng)請求,主動(dòng)向客戶端發(fā)送資源,即服務(wù)器推送(server push)

HTTP2.0和SPDY區(qū)別:

  • HTTP2.0 支持明文 HTTP 傳輸,而 SPDY 強(qiáng)制使用 HTTPS
  • HTTP2.0 消息頭的壓縮算法采用 HPACK,而非 SPDY 采用的 DEFLATE

1.4.7 HTTP 請求訪問的完整過程

image.png

一次完整的http請求處理過程:

1、建立連接:接收或拒絕連接請求
2、接收請求:接收客戶端請求報(bào)文中對(duì)某資源的一次請求的過程

Web訪問響應(yīng)模型(Web I/O)

image.png
  • 單進(jìn)程I/O模型:啟動(dòng)一個(gè)進(jìn)程處理用戶請求,而且一次只處理一個(gè),多個(gè)請求被串行響應(yīng)
  • 多進(jìn)程I/O模型:并行啟動(dòng)多個(gè)進(jìn)程,每個(gè)進(jìn)程響應(yīng)一個(gè)連接請求
  • 復(fù)用I/O結(jié)構(gòu):啟動(dòng)一個(gè)進(jìn)程,同時(shí)響應(yīng)N個(gè)連接請求
  • 復(fù)用的多進(jìn)程I/O模型:啟動(dòng)M個(gè)進(jìn)程,每個(gè)進(jìn)程響應(yīng)N個(gè)連接請求,同時(shí)接收M*N個(gè)請求

3、處理請求:服務(wù)器對(duì)請求報(bào)文進(jìn)行解析,并獲取請求的資源及請求方法等相關(guān)信息,根據(jù)方法,資源,首部和可選的主體部分對(duì)請求進(jìn)行處理

常用請求Method: GET、POST、HEAD、PUT、DELETE、TRACE、OPTIONS

4、訪問資源:

服務(wù)器獲取請求報(bào)文中請求的資源web服務(wù)器,即存放了web資源的服務(wù)器,負(fù)責(zé)向請求者提供對(duì)方請求的靜態(tài)資源,或動(dòng)態(tài)運(yùn)行后生成的資源

5、構(gòu)建響應(yīng)報(bào)文:

一旦Web服務(wù)器識(shí)別除了資源,就執(zhí)行請求方法中描述的動(dòng)作,并返回響應(yīng)報(bào)文。響應(yīng)報(bào)文中 包含有響應(yīng)狀態(tài)碼、響應(yīng)首部,如果生成了響應(yīng)主體的話,還包括響應(yīng)主體

1)響應(yīng)實(shí)體:如果事務(wù)處理產(chǎn)生了響應(yīng)主體,就將內(nèi)容放在響應(yīng)報(bào)文中回送過去。響應(yīng)報(bào)文中通常包括:

  • 描述了響應(yīng)主體MIME類型的Content-Type首部
  • 描述了響應(yīng)主體長度的Content-Length
  • 實(shí)際報(bào)文的主體內(nèi)容

2)URL重定向:web服務(wù)構(gòu)建的響應(yīng)并非客戶端請求的資源,而是資源另外一個(gè)訪問路徑
3)MIME類型: Web服務(wù)器要負(fù)責(zé)確定響應(yīng)主體的MIME類型。多種配置服務(wù)器的方法可將MIME類型與資源管理起來

  • 魔法分類:Apache web服務(wù)器可以掃描每個(gè)資源的內(nèi)容,并將其與一個(gè)已知模式表(被稱為魔法文件)進(jìn)行匹配,以決定每個(gè)文件的MIME類型。這樣做可能比較慢,但很方便,尤其是文件沒有標(biāo)準(zhǔn)擴(kuò)展名時(shí)
  • 顯式分類:可以對(duì)Web服務(wù)器進(jìn)行配置,使其不考慮文件的擴(kuò)展名或內(nèi)容,強(qiáng)制特定文件或目錄內(nèi)容擁有某個(gè)MIME類型
  • 類型協(xié)商: 有些Web服務(wù)器經(jīng)過配置,可以以多種文檔格式來存儲(chǔ)資源。在這種情況下,可以配置Web服務(wù)器,使其可以通過與用戶的協(xié)商來決定使用哪種格式(及相關(guān)的MIME類型)最好

6、發(fā)送響應(yīng)報(bào)文

Web服務(wù)器通過連接發(fā)送數(shù)據(jù)時(shí)也會(huì)面臨與接收數(shù)據(jù)一樣的問題。服務(wù)器可能有很多條到各個(gè)客戶端的連接,有些是空閑的,有些在向服務(wù)器發(fā)送數(shù)據(jù),還有一些在向客戶端回送響應(yīng)數(shù)據(jù)。服務(wù)器要記錄連接的狀態(tài),還要特別注意對(duì)持久連接的處理。對(duì)非持久連接而言,服務(wù)器應(yīng)該在發(fā)送了整條報(bào)文之后,關(guān)閉自己這一端的連接。對(duì)持久連接來說,連接可能仍保持打開狀態(tài),在這種情況下,服務(wù)器要正確地計(jì)算Content-Length首部,不然客戶端就無法知道響應(yīng)什么時(shí)候結(jié)束

7、記錄日志

最后,當(dāng)事務(wù)結(jié)束時(shí),Web服務(wù)器會(huì)在日志文件中添加一個(gè)條目,來描述已執(zhí)行的事務(wù)

瀏覽器訪問網(wǎng)站的底層實(shí)現(xiàn)流程:

瀏覽器訪問網(wǎng)站的過程
1. DNS解析

2. 路由尋址

3. 連接對(duì)方主機(jī)監(jiān)聽端口, 通過TCP三次握手建立連接

4. 客戶端發(fā)起http請求

5. 服務(wù)器端處理請求, 不同Web服務(wù)器通過不同邏輯處理, 見下面: <<一次http請求訪問的完整過程>>

中間還要涉及https 和 重定向技術(shù), strict-transport-security(HSTS)

6. 服務(wù)器得到處理結(jié)果, 封裝響應(yīng)報(bào)文頭部, 發(fā)給客戶端

7. 客戶端收到頁面后, 分析頁面代碼, 進(jìn)行解釋渲染, 展示頁面

8. 如果涉及動(dòng)態(tài)資源, 比如php或者jsp, 那還要發(fā)給后端的應(yīng)用程序服務(wù)器進(jìn)行處理, php-FastcCGI, 處理過程中有可能涉及到數(shù)據(jù)庫訪問, 還要連接MySQL進(jìn)行讀寫

一次http請求訪問的完整過程:

1. 建立連接:

URL → DNS (URL - IP ) → 接受或拒絕連接請求 → 三次握手建立通訊

2. 發(fā)送/接受請求:

客戶端發(fā)起HTTP請求: 客戶端開啟隨機(jī)端口號(hào), 通過TCP/IP套接字訪問Web服務(wù)器的80端口
服務(wù)器接受HTTP請求: Web服務(wù)器的80端口要保持在監(jiān)聽狀態(tài), 接受客戶端請求報(bào)文中對(duì)某資源的請求

服務(wù)器接收到請求后, 會(huì)予以相應(yīng)

3. 接受,響應(yīng)過程:

多種模型: 多種不同處理方案

  1. 串行, 單I/O模型: 來一個(gè)處理一個(gè)請求, 會(huì)造成申請排隊(duì)現(xiàn)象. (單進(jìn)程I/O). 每個(gè)連接只處理一個(gè)請求, 處理完連接斷開, 之后再次建立連接, 處理請求.

  2. 并行: 同時(shí)處理多個(gè)請求. (多進(jìn)程I/O). 缺點(diǎn): 建立太多的進(jìn)程, 每個(gè)進(jìn)程處理一個(gè)連接請求. CPU負(fù)載過高, 連接太多也會(huì)排隊(duì). 因?yàn)殡m然是多進(jìn)程, 但實(shí)際還是一個(gè)進(jìn)程處理一個(gè)請求, 當(dāng)連接數(shù)超過開啟的進(jìn)程數(shù)就會(huì)造成排隊(duì). 即使有CPU分片, 也會(huì)造成頻繁切換, 一個(gè)用戶的請求還沒有處理完, 就要去處理另一個(gè)請求, 那么CPU緩存中包含的此前的用戶請求處理信息有可能丟失. 真正干活的不是進(jìn)程, 而是CPU, 因此, 最終結(jié)果就是性能差. (Apache默認(rèn)處理方式,prefork). 高并發(fā)比不上Nginx, 但是多進(jìn)程工作, 起到進(jìn)程間隔離作用, 進(jìn)程之間互不影響. 因此, Apache穩(wěn)定.

  3. 復(fù)用的單進(jìn)程I/O結(jié)構(gòu): 只開啟單進(jìn)程, 通過連接復(fù)用器, 準(zhǔn)備一個(gè)連接池, 用來接收用戶連接. 利用CPU處理速度快的特性, CPU將請求提交到內(nèi)核, 發(fā)起系統(tǒng)調(diào)用, 向硬盤請求文件, 由于磁盤的I/O是很慢的, 因此CPU就有時(shí)間去處理后續(xù)的請求. 因此, 可以用單進(jìn)程, 利用處理間隙來支持并發(fā)連接. 減少了服務(wù)器開啟的進(jìn)程. Nginx單進(jìn)程處理方式

  4. 復(fù)用的多進(jìn)程I/O結(jié)構(gòu): 充分發(fā)揮多核CPU的優(yōu)勢, 開啟多個(gè)進(jìn)程, 每個(gè)進(jìn)程都支持復(fù)用的單進(jìn)場I/O. (Nginx多進(jìn)程處理方式). 因此Nginx處理高并發(fā)效果好.

適用場景:

Apache: 企業(yè)并發(fā)量不高, 但是追求穩(wěn)定. 10000(ss -nt)高并發(fā)(c10k問題). 多進(jìn)程處理, 起到隔離.
Nginx: 高并發(fā). 單機(jī)2-3萬, 或者更高, 看服務(wù)器配置.

4. 處理請求

服務(wù)器對(duì)請求報(bào)文進(jìn)行解析, 并獲取請求的資源及請求方法等相關(guān)信息, 根據(jù)方法, 資源, 首部和可選主體部分對(duì)請求進(jìn)行處理

常用的請求: GET, POST, HEAD, PUT, DELETE, TRACE, OPTIONS

5. 訪問資源

服務(wù)器獲取請求報(bào)文中請求的資源Web服務(wù)器, 即存放了Web資源的服務(wù)器, 負(fù)責(zé)向請求者提供對(duì)方請求的靜態(tài)資源, 或動(dòng)態(tài)資源后生成的資源.

6. 構(gòu)建響應(yīng)報(bào)文
7. 發(fā)送響應(yīng)報(bào)文
8. 記錄日志

1.4.8 Apache三種多路處理模塊工作原理和區(qū)別, MPM (Multi-Processing Module)

  • prefork: 多進(jìn)程IO模型, 每個(gè)進(jìn)程響應(yīng)一個(gè)請求, httpd2.4.6(CentOS7上的httpd默認(rèn)使用prefork), 也是早期的apache的默認(rèn)模型

一個(gè)主進(jìn)程(由root創(chuàng)建): 僅負(fù)責(zé)監(jiān)聽, 用于生成和回收多個(gè)子進(jìn)程, 創(chuàng)建套接字, 只負(fù)責(zé)請求的接收, 不負(fù)責(zé)具體的響應(yīng)
多個(gè)子進(jìn)程: 工作worker進(jìn)程, 每個(gè)子進(jìn)程中會(huì)開啟一個(gè)獨(dú)立的線程用于負(fù)責(zé)處理一個(gè)請求, 系統(tǒng)初始化時(shí), 預(yù)先生成多個(gè)空閑進(jìn)程, 等待請求

prefork MPM: 預(yù)派生模式, 由一個(gè)主控進(jìn)程, 生成多個(gè)子進(jìn)程, 每個(gè)子進(jìn)程中會(huì)有一個(gè)獨(dú)立的線程響應(yīng)用戶請求, 相對(duì)比較占用內(nèi)存, 但是比較穩(wěn)定, 可以設(shè)置最大和最小進(jìn)程數(shù), 適用于訪問量不是很大的場景

優(yōu)點(diǎn): 穩(wěn)定
缺點(diǎn): 慢, 占用資源, 不適用于高并發(fā)的場景

圖片.png
  • worker模型: 復(fù)用的多進(jìn)程IO模型, 多進(jìn)程多線程

一個(gè)主進(jìn)程(由root創(chuàng)建): 生成m個(gè)子進(jìn)程, 每個(gè)子進(jìn)程負(fù)責(zé)生成n個(gè)線程, 每個(gè)線程響應(yīng)一個(gè)請求, 并發(fā)響應(yīng)請求數(shù)量為m*n

worker MPM: 是一種多進(jìn)程和多線程混合的模型, 由一個(gè)主控制進(jìn)程, 啟動(dòng)多個(gè)子進(jìn)程, 每個(gè)子進(jìn)程里面包含固定的線程, 使用線程處理請求, 當(dāng)線程不夠使用時(shí), 會(huì)再啟動(dòng)一個(gè)新的子進(jìn)程, 然后在子進(jìn)程里面再啟動(dòng)線程處理請求, 由于其使用了多線程處理請求, 因此可以承受更高的并發(fā)

優(yōu)點(diǎn): 相比prefork占用的內(nèi)存較少, 因?yàn)樽罱K使用的是多個(gè)線程, 而線程相比進(jìn)程占用的內(nèi)存資源較少, 可以同時(shí)處理多個(gè)請求
缺點(diǎn): 當(dāng)使用keep-alive的長連接方式, 某個(gè)線程會(huì)被一直占用, 即使沒有傳輸數(shù)據(jù), 也需要一直等待到超時(shí)才會(huì)被釋放, 如果過多的線程, 被這樣占用, 也會(huì)導(dǎo)致在高并發(fā)場景下, 無服務(wù)線程可用, 該問題在prefork模式下也會(huì)發(fā)生. 此外, 單個(gè)進(jìn)程中的多個(gè)線程會(huì)出現(xiàn)資源競爭的情況, 如果一個(gè)線程出現(xiàn)問題, 會(huì)影響本進(jìn)程中的其他線程

圖片.png
  • event: 事件驅(qū)動(dòng)模型(worker模型的變種), httpd2.4.37(CentOS8上的httpd默認(rèn)使用event模型)的默認(rèn)模型

一個(gè)主進(jìn)程(由root創(chuàng)建): 生成m個(gè)子進(jìn)程, 每個(gè)子進(jìn)程負(fù)責(zé)生個(gè)n個(gè)線程, 每個(gè)工作線程響應(yīng)一個(gè)請求, 并發(fā)響應(yīng)請求數(shù)為:m*(n-1), n-1是因?yàn)楸O(jiān)聽線程不會(huì)處理請求, 僅負(fù)責(zé)調(diào)度, 有專門的監(jiān)控線程來管理這些keep-alive類型的線程, 當(dāng)有真實(shí)請求時(shí), 將請求傳遞給服務(wù)線程, 執(zhí)行完畢后, 又允許線程釋放. 或者將沒有請求處理的線程放在空閑線程. 這樣增加了高并發(fā)場景下的請求處理能力

event MPM: 屬于事件驅(qū)動(dòng)模型, epoll, 一個(gè)進(jìn)程響應(yīng)多個(gè)請求, 現(xiàn)在的版本已經(jīng)是穩(wěn)定可用的模式. 它和worker模型很像, 最大的區(qū)別在于, 它解決了keep-alive場景下, 長期被占用的線程的資源浪費(fèi)問題 (某些線程因?yàn)楸籯eep-alive, 空掛在那里等待, 中間幾乎沒有請求過來, 甚至等待超時(shí))

event MPM中, 會(huì)有一個(gè)專門的線程來管理這些keep-alive類型的線程, 當(dāng)有真實(shí)請求過來的時(shí)候, 將請求傳遞給服務(wù)線程, 執(zhí)行完畢后, 又允許線程被釋放. 這樣就可以增加高并發(fā)場景下的請求處理能力


圖片.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容