共創做者:張曉旭
掘金主頁:juejin.cn/user/852876…javascript
聊TCP/IP協議以前, 我們先看一下OSI七層模型.html
第 7 層:應用層 爲操做系統或網絡應用程序提供訪問網絡服務的接口。應用層協議的表明包括: HTTP,HTTPS,FTP,TELNET,SSH,SMTP,POP3等。 第 6 層:表示層 把數據轉換爲接受者可以兼容而且適合傳輸的內容,好比數據加密,壓縮,格式轉換等。 第 5 層:會話層 負責數據傳輸中設置和維持網絡設備之間的通訊鏈接。管理主機之間的會話進程,還能夠利用在數據中插入校驗點來實現數據的同步。 第 4 層:傳輸層 把傳輸表頭加至數據造成數據包,完成端到端的數據傳輸。傳輸表頭包含了協議等信息,好比: TCP,UDP 等。 第 3 層:網絡層 負責對子網間的數據包進行尋址和路由選擇,還能夠實現擁塞控制,網際互聯等功能。網絡層的協議包括:IP,IPX 等。好比路由器就在這 第 2 層:數據鏈路層 在不可靠的物理介質上提供可靠的傳輸,主要主要爲:物理地址尋址、數據封裝成幀、流量控制、數據校驗、重發等。好比交換機就在這 第 1 層:物理層 在局域網上傳送數據幀,負責電腦通訊設備與網絡媒體之間的互通,包括針腳,電壓,線纜規範,集線器,網卡,主機適配等。java
一些面試題:node
應用層linux
通俗點說:是協議定義了每一層的做用是什麼, 每一層的職責是什麼, 相似於規範和約束.面試
有的文章裏就是具體指的TCP協議和IP協議, 可是大多數時候提到的TCP/IP協議, 能夠理解爲互聯網通訊所須要的協議, 是一個協議家族, 以TCP、IP協議爲核心, 包含HTTP、SMTP、TELNET等各類協議。算法
TCP/IP參考模型是一個抽象的分層模型,這個模型中,全部的TCP/IP系列網絡協議都歸類到4個抽象的「層」中.chrome
能夠看一下圖 npm
數據包是網絡層及以上分層中包的單位.vim
每一個分層都會對發送的數據添加一個首部, 首部包含了該層協議相關的信息, 而真正要發送的內容稱之爲數據.
也就是說每個數據包都由首部 + 數據組成.
而對於下層來講, 上層發送過來的所有內容, 都會當作本層的數據, 舉個例子:
傳輸層 TCP包:TCP包首部 + 數據 網絡層 IP包:IP包首部 + (TCP包首部 + 數據) 數據鏈路層 以太網包:以太網包首部 + (IP包首部 + (TCP包首部 + 數據))
用戶1
用戶2
若是是發送給本身的包,則從以太網包首部中的類型肯定數據類型,再傳給相應的模塊,好比IP.
總結一下幾個地址:
答案是否認的.
咱們須要經過如下這幾個數據綜合來識別一次通訊:
那麼常見直播底層是什麼協議呢?
其實如今常見的rtmp和hls直播, 都是基於TCP的, 但願能提供穩定的直播環境.
擁塞控制就是防止過多的數據注入網絡中,這樣可使網絡中的路由器或鏈路不致過載。 發送方維持一個叫作擁塞窗口cwnd(congestion window)的狀態變量。 爲了防止cwnd增加過大引發網絡擁塞,還需設置一個慢開始門限ssthresh狀態變量。ssthresh的用法以下: 當cwnd<ssthresh時,使用慢開始算法。也就是乘法算法 當cwnd>ssthresh時,改用擁塞避免算法。也就是加法算法 當cwnd=ssthresh時,慢開始與擁塞避免算法任意。 當出現擁塞的時候就把心的門限值設爲此時窗口大小的通常,窗口大小設置爲1,再從新執行上面的步驟。 當收到連續三個重傳的時候這就須要快重傳和快恢復了,當收到連續三個重傳 這個時候發送方就要重傳本身的信息,而後門限減半可是這個時候並非網絡阻塞,窗口只會減半執行擁塞避免算法。
第一次握手:創建鏈接。客戶端發送鏈接請求報文段,將SYN位置爲1,Sequence Number爲x;而後,客戶端進入SYN_SEND狀態,等待服務器的確認; 第二次握手:服務器收到客戶端的SYN報文段,須要對這個SYN報文段進行確認,設置Acknowledgment Number爲x+1(Sequence Number+1);同時,本身本身還要發送SYN請求信息,將SYN位置爲1,Sequence Number爲y;服務器端將上述全部信息放到一個報文段(即SYN+ACK報文段)中,一併發送給客戶端,此時服務器進入SYN_RECV狀態; 第三次握手:客戶端收到服務器的SYN+ACK報文段。而後將Acknowledgment Number設置爲y+1,向服務器發送ACK報文段,這個報文段發送完畢之後,客戶端和服務器端都進入ESTABLISHED狀態,完成TCP三次握手。
完成了三次握手,客戶端和服務器端就能夠開始傳送數據。以上就是TCP三次握手的整體介紹。通訊結束客戶端和服務端就斷開鏈接,須要通過四次分手確認。
第一次分手:主機1(可使客戶端,也能夠是服務器端),設置Sequence Number和Acknowledgment Number,向主機2發送一個FIN報文段;此時,主機1進入FIN_WAIT_1狀態;這表示主機1沒有數據要發送給主機2了; 第二次分手:主機2收到了主機1發送的FIN報文段,向主機1回一個ACK報文段,Acknowledgment Number爲Sequence Number加1;主機1進入FIN_WAIT_2狀態;主機2告訴主機1,我「贊成」你的關閉請求; 第三次分手:主機2向主機1發送FIN報文段,請求關閉鏈接,同時主機2進入LAST_ACK狀態; 第四次分手:主機1收到主機2發送的FIN報文段,向主機2發送ACK報文段,而後主機1進入TIME_WAIT狀態;主機2收到主機1的ACK報文段之後,就關閉鏈接;此時,主機1等待2MSL後依然沒有收到回覆,則證實Server端已正常關閉,那好,主機1也能夠關閉鏈接了。
IP 地址(IPv4 地址)由32位正整數來表示,在計算機內部以二進制方式被處理。平常生活中,咱們將32位的 IP 地址以每8位爲一組,分紅4組,每組以 「.」 隔開,再將每組數轉換成十進制數
IP地址包含網絡標識和主機標識, 好比172.112.110.11
172.112.110就是網絡標識, 同一網段內網絡標識必須相同 11就是主機標識, 同一網段內主機標識不能重複
IPv6(IP version 6)是爲了根本解決 IPv4 地址耗盡的問題而被標準化的網際協議。IPv4 的地址長度爲 4 個 8 位字節,即 32 比特。而 IPv6 的地址長度則是原來的 4 倍,即 128 比特,通常寫成 8 個 16 位字節。
咱們平時訪問一個網站, 一個應用程序, 並非用ip來訪問的, 而是用一個域名. 那麼域名是怎麼和ip地址創建聯繫的呢?
就是經過dns, Domain Name System. 好比wiki上的一個例子
以訪問 zh.wikipedia.org 爲例:
客戶端發送查詢報文"query zh.wikipedia.org"至DNS服務器,DNS服務器首先檢查自身緩存,若是存在記錄則直接返回結果。 若是記錄老化或不存在,則: DNS服務器向根域名服務器發送查詢報文"query zh.wikipedia.org",根域名服務器返回頂級域 .org 的頂級域名服務器地址。 DNS服務器向 .org 域的頂級域名服務器發送查詢報文"query zh.wikipedia.org",獲得二級域 .wikipedia.org 的權威域名服務器地址。 DNS服務器向 .wikipedia.org 域的權威域名服務器發送查詢報文"query zh.wikipedia.org",獲得主機 zh 的A記錄,存入自身緩存並返回給客戶端。
在這以前我們要先來了解一下Socket的概念,
咱們常常把socket翻譯爲套接字,socket是在應用層和傳輸層之間的一個抽象層,它把TCP/IP層複雜的操做抽象爲幾個簡單的接口供應用層調用已實現進程在網絡中通訊, 好比create,listen,accept,connect,read和write等等。
node裏有各類網絡相關的模塊, http爲應用層模塊,主要按照特定協議編解碼數據;net爲傳輸層模塊,主要負責傳輸編碼後的應用層數據;https是個綜合模塊(涵蓋了http/tls/crypto等),主要用於確保數據安全性
const net = require('net');
const HOST = '127.0.0.1';
const PORT = 7777;
// 建立一個TCP服務器實例,調用listen函數開始監聽指定端口
// net.createServer()有一個參數, 是監聽鏈接創建的回調
net.createServer((socket) => {
const remoteName = `${socket.remoteAddress}:${socket.remotePort}`;
// 創建成功了一個鏈接, 這個回調函數裏返回一個socket對象.
console.log(`${remoteName} 鏈接到本服務器`);
// 接收消息
socket.on('data', (data) => {
console.log(`${remoteName} - ${data}`)
// 給客戶端發消息
socket.write(`你剛纔說啥?是${data}嗎?`);
});
// 關閉
socket.on('close', (data) => {
console.log(`${remoteName} 鏈接關閉`)
});
}).listen(PORT, HOST);
console.log(`Server listening on ${HOST}:${PORT}`);
複製代碼
const net = require('net');
const HOST = '127.0.0.1';
const PORT = 7777;
const client = new net.Socket();
const ServerName = `${HOST}:${PORT}`;
let count = 0;
client.connect(PORT, HOST, () => {
console.log(`成功鏈接到 ${ServerName}`);
// 向服務端發送數據
const timer = setInterval(() => {
if (count > 10) {
client.write('我沒事了, 告辭');
clearInterval(timer);
return;
}
client.write('馬冬梅' + count++);
}, 1000)
});
// 接收消息
client.on('data', (data) => {
console.log(`${ServerName} - ${data}`);
// 關閉鏈接
// client.destroy();
});
// 關閉事件
client.on('close', () => {
console.log('Connection closed');
});
client.on('error', (error) => {
console.log(error);
})
複製代碼
node tcp-server.js
node tcp-client.js
const dgram = require('dgram');
const server = dgram.createSocket('udp4');
server.on('message', (msg, remote) => {
console.log(`${remote.address}:${remote.port} - ${msg}`)
server.send(`收到!`, remote.port, remote.address);
})
server.on('listening', () => {
const address = server.address()
console.log(`Server listening on ${address.address}:${address.port}`);
})
server.bind(44444);
複製代碼
const dgram = require('dgram')
const message = Buffer.alloc(5, 'robozy')
const client = dgram.createSocket('udp4')
client.send(message, 0, message.length, 44444, 'localhost',
(err, bytes) => {
console.log(`發送成功${bytes}字節`);
// client.close()
}
)
client.on('message', (buffer) => {
console.log(buffer.toString())
})
複製代碼
node udp-server.js
node udp-client.js
HTTP協議(HyperText Transfer Protocol,超文本傳輸協議)是用於從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議。它可使瀏覽器更加高效,使網絡傳輸減小。它不只保證計算機正確快速地傳輸超文本文檔,還肯定傳輸文檔中的哪一部分,以及哪部份內容首先顯示(如文本先於圖形)等。 HTTP是客戶端瀏覽器或其餘程序與Web服務器之間的應用層通訊協議。在Internet上的Web服務器上存放的都是超文本信息,客戶機須要經過HTTP協議傳輸所要訪問的超文本信息。HTTP包含命令和傳輸信息,不只可用於Web訪問,也能夠用於其餘因特網/內聯網應用系統之間的通訊,從而實現各種應用資源超媒體訪問的集成。 咱們在瀏覽器的地址欄裏輸入的網站地址叫作URL (Uniform Resource Locator,統一資源定位符)。就像每家每戶都有一個門牌地址同樣,每一個網頁也都有一個Internet地址。當你在瀏覽器的地址框中輸入一個URL或是單擊一個超級連接時,URL就肯定了要瀏覽的地址。瀏覽器經過超文本傳輸協議(HTTP),將Web服務器上站點的網頁代碼提取出來,並翻譯成漂亮的網頁。
在HTTP工做開始以前,客戶端首先要經過網絡與服務器創建鏈接,該鏈接是經過 TCP 來完成的。HTTP 是比 TCP 更高層次的應用層協議,根據規則,只有低層協議創建以後,才能進行高層協議的鏈接,所以,首先要創建 TCP 鏈接,通常 TCP 鏈接的端口號是80;
一旦創建了TCP鏈接,客戶端就會向服務器發送請求命令; 例如:GET/info HTTP/1.1
客戶端發送其請求命令以後,還要以頭信息的形式向服務器發送一些別的信息,以後客戶端發送了一空白行來通知服務器,它已經結束了該頭信息的發送;
客戶端向服務器發出請求後,服務器會客戶端返回響應; 例如: HTTP/1.1 200 OK 響應的第一部分是協議的版本號和響應狀態碼
正如客戶端會隨同請求發送關於自身的信息同樣,服務器也會隨同響應向用戶發送關於它本身的數據及被請求的文檔;
服務器向客戶端發送頭信息後,它會發送一個空白行來表示頭信息的發送到此爲結束,接着,它就以 Content-Type 響應頭信息所描述的格式發送用戶所請求的實際數據;
通常狀況下,一旦服務器向客戶端返回了請求數據,它就要關閉 TCP 鏈接,而後若是客戶端或者服務器在其頭信息加入了這行代碼 Connection:keep-alive ,TCP 鏈接在發送後將仍然保持打開狀態,因而,客戶端能夠繼續經過相同的鏈接發送請求。保持鏈接節省了爲每一個請求創建新鏈接所需的時間,還節約了網絡帶寬。
協議規定, 請求從客戶端發出, 服務端響應請求並返回.
HTTP 是一種無狀態協議, 在單純HTTP這個層面,協議對於發送過的請求或響應都不作持久化處理
服務端返回的頭信息上有可能會攜帶Set-Cookie, 那麼當客戶端接收到響應後, 就會在本地種上cookie. 在下一次給服務端發送請求的時候, 就會攜帶上這些cookie。
這裏區分一下URI和URL的概念.
URI: 統一資源標識符, 好比你身份證號是xxxxxxx, 在全部人中是獨一無二的, 這個身份證號就能標識你的身份, 那麼它就是URI URL: 統一資源定位符, 好比北京市/朝陽區/xxxx/xxxx/xxxxx, 經過這一串信息能夠定位到你, 那麼這個就是URL
URL有點相似於經過定位實現的URI.
就像有個父類叫作URI, 他要實現的是惟一肯定一個id. 有的人喜歡繼承URI, 經過location來實現; 有的人喜歡繼承URI, 經過name來實現.
這裏指的是各類HTTP方法, 好比GET POST PUT DELETE等.
HTTP 協議的初始版本中,每進行一個 HTTP 通訊都要斷開一次 TCP 鏈接,增長了不少不必的創建鏈接的開銷。 爲了解決上述 TCP 鏈接的問題,HTTP/1.1 支持持久鏈接。其特色是,只要任意一端沒有明確提出斷開鏈接,則保持 TCP 鏈接狀態。旨在創建一次 TCP 鏈接後進行屢次請求和響應的交互。在 HTTP/1.1 中,全部的鏈接默認都是持久鏈接。
也就是說默認狀況下創建 TCP 鏈接不會斷開,只有在請求報頭中聲明 Connection: close 纔會在請求完成後關閉鏈接。
1.1版本引入pipelining機制, 即在同一個TCP鏈接裏面,客戶端能夠同時發送多個請求。
舉例來講,客戶端須要請求兩個資源。之前的作法是,在同一個TCP鏈接裏面,先發送A請求,而後等待服務器作出迴應,收到後再發出B請求。管道機制則是容許瀏覽器同時發出A請求和B請求,可是服務器仍是按照順序,先回應A請求,完成後再回應B請求。
可是現代瀏覽器通常沒開啓這個配置, 這個機制可能會形成隊頭阻塞. 由於響應是有順序的, 若是一個TCP鏈接中的第一個HTTP請求響應很是慢, 那麼就會阻塞後續HTTP請求的響應.
因此現實中默認狀況下, 一個TCP鏈接同一時間只發一個HTTP請求.
有的同窗會問, 我怎麼據說chrome最大支持6個同域名請求呢?
那是由於chrome最大支持同時開啓6個TCP鏈接。
每次TCP鏈接只能發送一個請求,當服務器響應後就會關閉此次鏈接,下一個請求須要再次創建TCP鏈接.
默認採用持續鏈接(TCP鏈接默認不關閉,能夠被多個請求複用,不用聲明Connection: keep-alive). 增長了管道機制,在同一個TCP鏈接裏,容許多個請求同時發送,增長了併發性,進一步改善了HTTP協議的效率, 可是同一個TCP鏈接裏,全部的數據通訊是按次序進行的。迴應慢,會有許多請求排隊,形成"隊頭堵塞"。
加了雙工模式,即不只客戶端可以同時發送多個請求,服務端也能同時處理多個請求,解決了隊頭堵塞的問題。 使用了多路複用的技術,作到同一個鏈接併發處理多個請求,並且併發請求的數量比HTTP1.1大了好幾個數量級。 增長服務器推送的功能,不經請求服務端主動向客戶端發送數據。
經過指定首部字段 Cache-Control 的指令,就能操做緩存的工做機制。
當指定使用 public 指令時,則明確代表其餘用戶也可利用緩存。
當指定 private 指令後,響應只以特定的用戶做爲對象,這與 public 指令的行爲相反。緩存服務器會對該特定用戶提供資源緩存的服務,對於其餘用戶發送過來的請求,代理服務器則不會返回緩存。
能夠在客戶端存儲資源,每次都必須去服務端作過時校驗,來決定從服務端獲取新的資源(200)仍是使用客戶端緩存(304)。也就是所謂的協商緩存。
永遠都不要在客戶端存儲資源,永遠都去原始服務器去獲取資源。
當客戶端發送的請求中包含 max-age 指令時,若是斷定緩存資源的緩存時間數值比指定的時間更小,那麼客戶端就接收緩存的資源。另外,當指定 max-age 的值爲0,那麼緩存服務器一般須要將請求轉發給源服務器。
HTTP/1.1 版本的緩存服務器遇到同時存在 Expires 首部字段的狀況時,會優先處理 max-age 指令,並忽略掉 Expires 首部字段
s-maxage 指令的功能和 max-age 指令的相同,它們的不一樣點是 s-maxage 指令只適用於供多位用戶使用的公共緩存服務器(通常指代理)。 當使用 s-maxage 指令後,則直接忽略對 Expires 首部字段及 max-age 指令的處理
HTTP/1.1 版本的默認鏈接都是持久鏈接。當服務器端想明確斷開鏈接時,則指定 Connection 首部字段的值爲 close。
HTTP/1.1 以前的 HTTP 版本的默認鏈接都是非持久鏈接。爲此,若是想在舊版本的 HTTP 協議上維持持續鏈接,則須要指定 Connection 首部字段的值爲 Keep-Alive。
代表建立 HTTP 報文的日期和時間。 Date: Mon, 10 Jul 2021 15:50:06 GMT HTTP/1.1 協議使用在 RFC1123 中規定的日期時間的格式。
Pragma 首部字段是 HTTP/1.1 版本以前的歷史遺留字段,僅做爲與 HTTP/1.0 的向後兼容而定義。
該首部字段屬於通用首部字段,但只用在客戶端發送的請求中,要求全部的中間服務器不返回緩存的資源。
全部的中間服務器若是都能以 HTTP/1.1 爲基準,那直接採用 Cache-Control: no-cache 指定緩存的處理方式最爲理想。可是要總體掌握全部中間服務器使用的 HTTP 協議版本倒是不現實的,因此,發送的請求會同時包含下面兩個首部字段:
Cache-Control: no-cache
Pragma: no-cache
複製代碼
Accept 首部字段可通知服務器,用戶代理可以處理的媒體類型及媒體類型的相對優先級。可以使用 type/subtype 這種形式,一次指定多種媒體類型。
Accept-Encoding 首部字段用來告知服務器用戶代理支持的內容編碼及內容編碼的優先順序,並可一次性指定多種內容編碼 也可以使用星號(*)做爲通配符,指定任意的編碼格式。
gzip 代表實體採用 GNU zip 編碼 compress 代表實體採用 Unix 的文件壓縮程序 deflate 代表實體採用 zlib 的格式壓縮的 identity 代表沒有對實體進行編碼,當沒有 Content-Encoding 首部字段時,默認採用此編碼方式
形如 If-xxx 這種樣式的請求首部字段,均可稱爲條件請求。服務器接收到附帶條件的請求後,只有判斷指定條件爲真時,纔會執行請求。
用於確認代理或客戶端擁有的本地資源的有效性。 在指定 If-Modified-Since 字段值的日期時間以後,若是請求的資源都沒有過更新,則返回狀態碼 304 Not Modified 的響應
首部字段 ETag 能告知客戶端實體標識。它是一種可將資源以字符串形式作惟一性標識的方式。服務器會爲每份資源分配對應的 ETag 值。 另外,當資源更新時,ETag 值也須要更新。生成 ETag 值時,並無統一的算法規則,而僅僅是由服務器來分配。
用於指定 If-None-Match 字段值的實體標記(ETag)值與請求資源的 ETag 不一致時,它就告知服務器處理該請求。
首部字段 User-Agent 會將建立請求的瀏覽器和用戶代理名稱等信息傳達給服務器。 由網絡爬蟲發起請求時,有可能會在字段內添加爬蟲做者的電子郵件地址。此外,若是請求通過代理,那麼中間也極可能被添加上代理服務器的名稱。
首部字段 Allow 用於通知客戶端可以支持 Request-URI 指定資源的全部 HTTP 方法。 當服務器接收到不支持的 HTTP 方法時,會以狀態碼 405 Method Not Allowed 做爲響應返回。與此同時,還會把全部能支持的 HTTP 方法寫入首部字段 Allow 後返回。
首部字段 Content-Encoding 會告知客戶端服務器對實體的主體部分選用的內容編碼方式。內容編碼是指在不丟失實體信息的前提下所進行的壓縮。
首部字段 Content-Type 說明了實體主體內對象的媒體類型。和首部字段 Accept 同樣,字段值用 type/subtype 形式賦值。
首部字段 Expires 會將資源失效的日期告知客戶端。 緩存服務器在接收到含有首部字段 Expires 的響應後,會以緩存來應答請求,在 Expires 字段值指定的時間以前,響應的副本會一直被保存。當超過指定的時間後,緩存服務器在請求發送過來時,會轉向源服務器請求資源。
const http = require('http')
http.createServer(function (req, res) {
res.writeHead(200, {
'Content-Type': 'text/plain'
})
res.end('Hello World')
}).listen(80, '127.0.0.1')
console.log('Server running at http://127.0.0.1:80/')
複製代碼
curl -v http://127.0.0.1:80
看一下請求報文
// 三次握手
* Rebuilt URL to: http://127.0.0.1:80/
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 80 (#0)
// 客戶端向服務端發送請求報文
> GET / HTTP/1.1
> Host: 127.0.0.1:80
> User-Agent: curl/7.54.0
> Accept: */*
>
// 服務端響應客戶端內容
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Wed, 04 Aug 2021 15:55:55 GMT
< Connection: keep-alive
< Keep-Alive: timeout=5
< Transfer-Encoding: chunked
<
* Connection #0 to host 127.0.0.1 left intact
Hello World%
複製代碼
const http = require('http')
const options = {
hostname: '127.0.0.1',
port: 80,
path: '/',
method: 'GET'
}
const req = http.request(options, (res) => {
console.log(`Status=${res.statusCode}, Headers=${JSON.stringify(res.headers)}`);
res.setEncoding('utf8')
res.on('data', (data) => {
console.log(data)
})
})
req.end()
複製代碼
談到部署, 確定得先有一個本身的服務器...
選ecs服務器, 按量付費/月/年 都行, 隨便選個鏡像便可.
wget https://nodejs.org/dist/v10.9.0/node-v10.9.0-linux-x64.tar.xz
tar xf node-v10.9.0-linux-x64.tar.xz
ln -s /root/node-v10.9.0-linux-x64/bin/node /usr/local/bin/node
ln -s /root/node-v10.9.0-linux-x64/bin/npm /usr/local/bin/npm
node -v
npm -v
npm config set registry https://registry.npm.taobao.org
npm install -g pm2
ln -s /root/node-v10.9.0-linux-x64/bin/pm2 /usr/local/bin/
ssh-keygen -t rsa
demo_id_rsascp ~/.ssh/demo_id_rsa.pub root@39.107.238.161:/root/.ssh/authorized_keys
vi ~/.ssh/config
Host robozy
HostName 39.107.238.161
User root
Port 22
IdentityFile ~/.ssh/demo_id_rsa
複製代碼
vim /etc/ssh/sshd_config
PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys
ssh robozy
rsync -avzp -e "ssh" ./Internet/ robozy:/root/app
pm2 start /root/app/http-server.js
10.1 新建deploy.sh文件
#!/bin/bash
HOST=robozy
rsync -avzp -e "ssh" ./Internet/ $HOST:/root/app
ssh $HOST "pm2 restart /root/app/http-server.js"
echo 'deploy success'
複製代碼
10.2 初始化npm命令
npm init
新增scripts "deploy": "./deploy.sh"
10.3 發佈
npm run deploy
const http = require('http')
const host = '0.0.0.0';
const port = 80;
http.createServer(function (req, res) {
res.writeHead(200, {
'Content-Type': 'text/plain'
})
res.end('Hello World')
}).listen(port, host)
console.log(`Server running at http://${host}:${port}/`)
複製代碼
netstat -tpln
39.107.238.161:80
共創做者:張曉旭
掘金主頁:juejin.cn/user/852876…