--- tags: System Architecture --- Internet Protocol === # TCP/IP 網路協議 * [jupyter notebook 架構分析](https://blog.just4fun.site/jupyter-notebook-architecture.html) 本篇是基於以下這本好書為開始,將自己所看的網路相關知識做簡單紀錄: ![](https://i.imgur.com/b887Zs3.jpg) <br> ## 為什麼想看這本書: 1. 現今IT發展已經脫離不了網路通訊,包含各種數據處理也是需要透過網路進行各種活動,而TCP/IP毫無疑問是現今最普遍的標準協定。 2. 處理資料的軟體工具(Kafka、Elastic Search、all kind of Data Base....等),大多是基於TCP/IP傳輸層上另外設計應用層的協定,雖然不了解網路協定還是可以使用這些工具,但了解網路協議有助於更深入了解這些工具,例如: * 案例1.Docker 的 Bridge 模式網路會在主機建立一組docker0的虛擬網橋(software bridge),其作用和實體交換機類似,這樣可以讓主機上相同bridge的不同容器連線溝通,而且 docker bridge driver 會自動在 Host 上設定相對應的 rule(iptables, network namespace),讓 container 的網路可以正確的被使用,而更下層機制是藉由在主機上建立一對虛擬網卡veth pair裝置,Docker將veth pair裝置的一端放在新建立的容器中,並命名為eth0(容器的網絡卡),另一端放在主機中,以vethxxx這樣類似的名字命名,並將這個網路裝置加入到docker0網橋中來實現,有這些認知,在部屬多容器上可以更深入的理解。 [Docker Bridge Network 簡介](https://godleon.github.io/blog/Docker/docker-network-bridge/) ![](https://i.imgur.com/4n6RL3e.jpg) * 案例2.Kafka就是基於TCP上另外建立應用層的通訊協定,以便達到"multiplex requests, the ability to simultaneously poll many connections"...等目的。 [The Explanation Behind The Protocols That Kafka Is Using](https://streamdata.io/blog/explanation-behind-protocols-that-kafka-is-using/) * 案例3 * [Top 15 Standard IoT Protocols That You Must Know About](https://www.ubuntupit.com/top-15-standard-iot-protocols-that-you-must-know-about/) ## OSI 7 層模型 ### 前導-網路協定(protocol) * 協定: * 比喻方式來說,協定就是共同的約定,就像語言一樣,英文可以算是是一種協定,在這協定下不同母語可以透過語言來通訊。 * 本質上來說,電腦間可以透過網際網路實現通訊,就是依靠大家都認同的機制來達成,這些機制統稱為協定,其必須在定義的『作用』下約定共同『規格』,『規格』內容就包含通訊方法,例如對講機的通訊可以視為是一種協定,其必須在約定的頻率和實體裝置下才能進行溝通。 * 補充-網際網路: * 網際網路(Internet):我們所知的網際網路已經變成是一個專有名詞,表示為透過**協定**連接全世界裝置的龐大網絡,很多人會將其和 WWW 劃上等號,但是他們是不同的事情。 * 網路的應用:我們所熟悉的 WWW、HTTP、FTP、E-mail...等都是建立在網際網路上較頂層的應用,其下是靠各種層面**基礎協定**來支撐,而目前最廣泛應用通訊協定就是TCP/IP。 ### 協定理想標準與層級化: * 一個完整的通訊,涉及了各種複雜的過程,很自然的,協定可以因應作用的不同而分出不同層次以簡化問題,通訊兩方同層次會盡量作到可以獨立變動而不影響其他層的運作,但以整體通訊角度來看,上層的功能需要以下層功能為基礎才能達到網路通訊目的。 * 以電話來比喻的話,電話設備互相連結機制是一種基礎的協定;聲音傳遞機制是層次較高的協定;而溝通用的語言(中文)又是更高層次的溝通協定,語言層次可以隨意更換(中文換英文)而不影響下層電話本身的通訊,反之改用對講機的話也不影響語言的選定,上層語言溝通必須靠下層電話網絡基礎才能實現。 * 網路通訊比電話複雜許多,因此想藉由分層來將功能分割,讓網路協定變的更簡單且具獨立性,而理想上理論模型就是**OSI的7層**架構,在分層架構下,下層級會接收特定服務,再為上層級提供特定服務,而各層之間的溝通約定就是協定,雖然其層次分的太細,實務上實現有點難度,但是是值得了解的一個架構。 * ***協定分層概念*** ![分層概念](https://i.imgur.com/fie2F6w.jpg) ### OSI 7 層模型各層簡介 * 下圖簡單介紹OSI的7層模型: ![](https://i.imgur.com/44q32Iq.jpg) 1. 實體層(Physical Layer): * 電腦的位元串(0/1)與實際物理線路上的高低電壓(或燈光閃爍)...等傳遞連結的協定 * 主要媒介是網路卡及網路線...等,而每個網路卡都有實體位址MAC。 2. 資料連結層(Data Link Layer): * 在實體層直接連接的節點間(ex:乙太網路直接連線的電腦),適用資料連結層。 * 資料連結層將實體層的數位訊號封裝成一組符合邏輯傳輸資料,這組訊號稱為資料訊框(Data Frame),訊框內包含媒體存取控制(Media Access Control,MAC)位址。 * 訊框就是真實資料前段約定好格式的表頭資料, 可以想像程對講機講話時要先調好的頻率,或是古代祕密通訊要先有暗號一樣 * 其實各層的協定都有各自約定好的表頭格式(自己層的暗號) * 不少網路協定是在資料連結層上運作,我們較常聽到的是非同步傳輸模式(Asynchronous Transfer Mode,ATM),以及點對點協定(Point-to-Point Protocol,PPP),網路交換器(Switch)是這個層級常見的設備,主要在區域網路上運作,先前 Docker bridge 的交換器類似本設備的軟體實現。 3. 網路層(Network Layer): * 網路層定義**網路路由**及定址功能將多個網路連結起來,以便讓通訊端點共同執行封包處理作業,是不直接實體連接端點可以通訊的重要協定 * 在TCP/IP中,本層最重要的協定就是網際網路協定(Internet Protocol,IP) * 資料在傳輸時,該協定將IP位址加入傳輸資料內,並把資料組成封包(Packet),在網路上傳輸時,封包裡面的IP位址會告訴網路設備這筆資料的來源及目的地 * 我們常用的網址,本質上就是 IP 的另一種表現方式 * 路由器及 Layer3 交換器即屬於第三層的網路設備,主要以IP作為資料傳輸依據,它們大多在企業機房內運作。 4. 傳輸層(Transport Layer): * IP 找到端點電腦後,透過傳輸層在兩台主機間創造邏輯性的通訊,白話一點就是找到對方主機後,怎麼讓應用程式溝通(Ex: E-mail, HTTP, FTP...) * 在TCP/IP中,傳輸層透過連接埠編號(port)辨別應用程式, * 傳輸層還負責電腦整體的資料傳輸及控制,是OSI模型中的關鍵角色,它可以將一個較大的資料切割成多個適合傳輸的資料,替模型頂端的第五、六、七等三個通訊層提供流量管制及錯誤控制。 * 傳輸控制協定(Transmission Control Protocol,TCP)是我們常接觸具有傳輸層功能的協定,它在傳輸資料內加入驗證碼,當對方收到後,就會依這個驗證碼,回傳對應的確認訊息(ACK),若對方未及時傳回確認訊息,資料就會重新傳遞一次,以確保資料傳輸的完整性。 5. 交談層(Session Layer): * 一種資料流動的邏輯性通訊路徑(邏輯路徑對比是實體路徑),負責建立或切斷通訊連結/設定傳輸資料的分割等,進行與資料傳輸有關的管理。 * 白話一點說,靠傳輸層的 port 找到對應應用程式後,可以進一步靠 session 連接或切斷時機 * 有很多應用服務運作在交談層上,我們常接觸到的是 NetBIOS names,這是一種用來識別電腦使用 NetBIOS 資源的依據。我們使用Windows 系統時,開啟網路上的芳鄰,或是用到「檔案及列印分享」時,通常會看到群組及電腦名稱,這些就是NetBIOS names定義的。 6. 表現層(Presentation Layer): * 具體來說,本層就是設備原有的資料表現格式 與 網路共用的資料格式的轉換 * 應用層收到的資料後,透過表現層轉換成適合通訊的資料格式,或將下層傳來的資料轉換成上層可以處理的資料格式 * 例如: 將 ASCII 編碼轉成應用層可以使用的資料,或是處理圖片及其他多媒體檔案,如 JPGE 圖片檔或 MIDI 音效檔,。 * 除了轉檔,有時候當資料透過網路傳輸時,需要將內容予以加密或解密,而這個工作就是在展示層中處理。 7. 應用層(Application Layer): * 各種我們使用的應用程式中,與通訊有關的部份,常見的通訊協定,有: * DHCP(Dynamic Host Configuration Protocol) * FTP(File Transfer Protocol) * HTTP(HyperText Transfer Protocol) * POP3(Post Office Protocol-Version 3) * 依據不同的網路服務方式,這些協定能定義各自的功能及使用規範等細部規則 * 屬於第七層的應用軟體,像是網路瀏覽器(IE、Firefox)、電子郵件、線上遊戲、即時通訊(MSN Messenger、ICQ)等 * 上述軟體均透過單一或多種通訊協定,提供各類網路應用服務,像是網路瀏覽器藉由HTTP的溝通,即可呈現圖文並茂的網頁 ## 通訊方式與種類 * 連接導向與非連接導向: * 連接導向: * 傳送資料前在兩端主機先建立連線 * 很像再打電話,需要先撥通 * 例如網頁間資訊傳輸 * 非連接導向: * 不會先進行建立,切斷連接處理 * 傳送端主機隨時可以傳送資料 * 例如:電子郵件 * 因應不同使用場景,兩種方式各有其優缺點 * 電路交換與封包交換: * 電路交換: * 利用電話線傳輸,歷史悠久 * 交換機負責中繼處理,連接後線路就被佔用,直到被切斷為止 * 如果多台電腦彼此想利用電路傳送資料的話會出現很多問題 * 封包交換(Packet): * 為了充分運用網路線路,以及預防網路斷訊風險...等考量,網路傳輸放棄在兩端點的電路交換網絡,改而提出封包交換網絡 * 封包交換是透過**路由器**連接通訊路線,把資料當作封包傳送,路由負責接收 * TCP/IP協定就是採用封包交換來傳遞資料,也就是將資料分拆成無數個小片段,僅在資料片段開頭加上各層的重要資訊(又稱表頭)後,其讓端點負責重組封包並在遺失封包時提出要求 * 這大幅簡化網路本身功能的舉動反而成功整合了各種不同的網絡。 ## TCP/IP 網路協定 * TCP/IP:TPC/IP的前身是一個為了驗證封包交換技術而建立的實驗性網路,後來才發展初TCP/IP,其算是一種比較務實的分層架構,也可以視為OSI 7層模型的簡化,其每一層的功能大致可以互相對應。廣義來說,TCP/IP 就是以**IP網路層**協定為基礎,往上層另外延伸的協定集合總稱,所以其不只是某一個協定名稱而已。 * 網際網路(Internet)與TCP/IP關係:之前提過網際網路就是連結所有設備形成一個大龐大網路,想藉由網際網路進行通訊時,就需要使用協定,而TCP/IP就是為了使用網際網路而開發的協定。 ## TCP/IP層級說明: ***OSI vs TCP/IP*** ![OSI vs TCP/IP](https://i.imgur.com/1AL9fbn.jpg) * 硬體:TCP/IP最下層是負責物理傳輸的硬體,這硬體是指乙太網路、電話線路或是其他無線設備...等實體層。 * 網路界面層:類比OSI的資料連結層,是利用乙太網路...等的資料連結,進行通訊的界面層級,可以視為是啟動網路卡(NIC)的驅動程式。 * 網際網路層:相當於OSI的網路層,其IP協定(Internet Protocol)就是TCP/IP協議的最重要基礎,其就是跨網路傳送封包,將封包傳送到整個網際網路的協定,IP協定下可以根據IP位址讓網路任兩台電腦互相連結並傳遞封包,我們常聽到的路由器就是以IP位址為主的交換器,其可以根據IP轉發封包,或讓不同的資料連結。此外,IP協定下傳送封包並沒有保證資料傳送的完整行,是屬於缺乏可靠性的協定,這需要其他協定來補足。 * ICMP(Internet Control Message Protocol): 傳送IP封包出現問題時會提出異常通知的協定,有時會用來診斷網路狀態。 * ARP(Address Resolution Protocol):從IP位址取的封包傳送端物理位址(MAC)的協定。 * 傳輸層:傳輸層就是基於IP層上,進一步建立各種應用程式間的通訊協定(Email, HTTP, FTP...等),而連接埠編號(Port)就是用來辨別應用程式用的,其可以視為應用程式的位址,TCP/IP有兩個最具代表性的傳輸協定,就是 TCP & UDP: * TCP(Transmission Control Protocol):連接導向且具有可靠性的傳輸協定,能確保兩端主機的資料都可以正確傳輸,也因此會產生很多確認機制,也因此較不適合視訊/聲音/影像...等一定時間內要傳輸一定資料量的通訊。 * UDP(User Datagram Protocol):屬於非連接導向且沒有可靠性的傳輸層協定,非常適合影像或聲音...等多媒體通訊。 * 應用層:TCP/IP層級模型中,將OSI的交談層/表現層/應用層...等功能,全部交給應用程式來處理,以下以網頁應用為例: * WWW:是將網際網路上的資料以超文字(HyperText)形式呈現在瀏覽器上的系統,也是讓網際網路普及的重要動力。 * HTML:就是這系統上主要的共用資料格式,透過瀏覽器,可將HTML文件主體內容作解析後,進行畫面並呈現給使用者。 * HTTP:就是定義上述HTTP資料傳輸方式的通訊協定,整體架構於TCP/IP之上,其特色是基於請求/回應模式,以及無狀態協定...等特色。 以上是瀏覽器網頁的相關應用層協定; 其他像發信時會用SMTP; 收信時會用POP3...等不同的應用層協定。 ## TCP/IP資料傳送流程: ***TCP/IP Flow*** ![](https://i.imgur.com/MCCctRC.jpg) 以上圖為例,以下簡述TCP/IP資料傳送流程, 1. 最上層使用者注重的是文字內容的表達,而在按下傳送後,E-mail應用程式處理通訊部份就開始工作,應用程式會決定這封信該怎麼使用下層TCP的協定來傳送,例如:是整間公司累積5封信後一起傳送?還是一封一封各自傳送,Email是否要依照特定格式去寫...等,都是應用層的決定範圍。 2. 下層TCP協定接收到上層信件的資料後,開始將資料處理成封包並加上TCP的表頭後往下IP層傳遞,而TCP這裡主要的功用就是建立讓這資料可以在相通的E-mail程式去通訊,並且為了保證所有封包對方都可以收的到,TCP另外會先確認對方是否有連線,並且在最後確認封包都有收到沒有遺漏...等,這些動作都是IP層沒有作到的。 3. IP層接收到資料後會加上IP層的表頭,並且想辦法把資料送到對方的電腦(非應用程式),當中怎麼靠IP找到對方電腦都是IP層負責處理的,可以想像成IP層就像電話,其負責可以連到另一個電話,但聲音要怎麼保證清楚的傳過去則是靠上層的TCP協定處理。 4. IP層以下就是電腦資料透過網卡將資料傳到網路(線)的物理機制了。 ## 什麼是 Socket(套接字): 乾貨: [Socket Programming in Python (Guide)](https://realpython.com/python-sockets/) * 學習網路通訊編程,常常是以Socket套件操作開始,其實Socket不是一個層,最初是UNIX系統下利用網路通訊的一種API,本質上就是一個介面程式(Interface),介於TCP層和應用層之間,目的是把TCP/IP封裝好,讓應用層的協定可以方便快速的使用TCP/IP協定; 以一般的程式操作角度來看,大家可以把Socket當作是(抽象為)對於檔案I/O的一個操作 ***socket*** ![](https://i.imgur.com/YEY2Hgn.jpg) 以下是用Python的Socket模組建立簡單的Client & Server互動範例: ![](https://i.imgur.com/Eql1Dtc.jpg) [Simple TCP server by Python Socket Module](https://github.com/EricYangsw/tcp_ip/blob/master/server_client/simple_tcp_server.ipynb) ```Python #python3 import sys import socket import threading # Simple TCP Server bind_ip = "0.0.0.0" bind_port = 9999 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind((bind_ip, bind_port)) server.listen(5) print("[*] Listening on %s:%d" %(bind_ip, bind_port)) def handle_client(client_socket): request = client_socket.recv(1024) print("[*] Received: %s" % request) client_socket.send(b'ACK!') client_socket.close() while True: client, addr = server.accept() print("[*] Accpeted connection from: %s:%d" % (addr[0], addr[1])) client_handler = threading.Thread(target=handle_client, args=(client,)) client_handler.start() # Showing port number in ubuntu system !netstat -t -u -a -p # On jupyter notebook $ netstat -t -u -a -p #On bash ``` [Simple TCP Client by Python Socket Module](https://github.com/EricYangsw/tcp_ip/blob/master/server_client/simple_tcp_client.ipynb) ```Python import sys import socket import threading # Connect to google webpage target_host = "www.google.com" target_port = 80 # build socket object: # AF_INET = IPv4; SOCK_STREAM = TCP client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((target_host, target_port)) client.send(b'GET / HTTP/1.1\r\nHost: google.com\r\n\r\n') response = client.recv(4096) print(response) # Connect to ourself server target_host = "0.0.0.0" target_port = 9999 # build socket object: # AF_INET = IPv4; SOCK_STREAM = TCP client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((target_host, target_port)) client.send(b'Try to connect to server yaya~~~') response = client.recv(4096) print(response) ``` ## 其他IP相關重要知識: 1. IPv4 & IPv6: IPv4是目前最普遍的IP層協定的格式,其是由4個小於255的數字組成(EX:255.255.255.255),以二進位表示的話,可以算出總共有2的32次方的組合,而這數字在現今網路世界已經快不夠用(想像成電話號碼不夠每個電話配一個號碼了),雖然有各種虛擬IP位址的技術出現,但還是無法解決這問題,因此IPv6的出現最主要就是為了解決這個問題,只是IPv6目前尚未完全普及。 2. DNS(Domain Name System):平常使用網路時,大部分時間都不會碰到IP位址,這是因為我們建立起字元與IP位址的對應關係,也就是域名,而這對應的系統就是DNS,這樣IP位址就可以轉換成我們人類比較好記的形式,我們在瀏覽器輸入網址的時候,www之後的域名都會透過DNS轉成對易的主機IP。 3. URI(Uniform Resource Identifier):是呈現資源的表記方法,在早期,是先有URL(Uniform Resource Locator)和URN(Uniform Resource Name),後來才全部整合進URI,也就是說URL和URN是URI的子集合。 * URL:主要目的是以文字方式說明網路上的資源如何取得,格式範例如下: * 通用 : < scheme >:< scheme-specific-part > * HTTP: http:openhome.cc:8080/Gossip/incex.html * URN:代表某個資源獨一無二的名稱,早期主要語法格式如下: * < URN > ::="urn:"< NID > ":" < NSS > * urn:isbn:978-986-476-675-8 (EX: 書的國際標準書號) * URI: * URI = scheme ":" hier-part ["?" query] [ "#" fragment ] hier-part = "//" or "/" * foo://example.com:8042/over/there?name=ferret#nose 4. URI(URL) 和 DNS 關係:當URI解析出域名後,需要靠DNS將域名解析出對應IP,如果才能靠協定找到對應的主機。 [URL、域名、DNS解析](https://www.jianshu.com/p/ecdc9abb13d5) # Python 爬蟲 --- ## 基本觀念: 爬蟲基本動作可以歸納為以下循環: 1. 取得網站的 HTML: * 一個網頁本質上就是一堆 HTML文字,根據 URL透過 Requests送出請求取得 HTML內容。 2. 解析資料以取得目標資訊: * 透過瀏覽器的開發者工具,觀察目標資訊位置 * 透過 BeautifulSoup(Python tool) 解析 HTML * 將資料以某種格式(CSV, JSON)寫入或是存到資料庫 3. 堤取頁面中的鏈結: 資料往往不只在一個頁面,因此必須分析出其他連結,在繼續進行分析後爬取目標內容。 ## Scrapy 爬蟲軟體 Scrapy是一個用 Python撰寫,基於 **Twisted**網路引擎框架,的開源網路爬蟲架構,幾個主要依賴套件如下: * lxml: 一個高效率的XML/HTML解析套件 * parsel: 基於 lxml的 XML/HTML的資料探索庫 * w3lib: 處理 URLs和網頁編碼的多用途協助程序 * twisted: 非同步網路引擎框架 * cryptography & pyOpenSSL: 處理各種網路層級安全需求 ### Scrapy install ```bash # install scrapy $ pip install scrapy # by anaconda $ conda install -c conda-forge scrapy # Test in shell $ scrapy Scrapy 1.5.2 - no active project Usage: scrapy <command> [options] [args] Available commands: bench Run quick benchmark test fetch Fetch a URL using the Scrapy downloader genspider Generate new spider using pre-defined templates runspider Run a self-contained spider (without creating a project) settings Get settings values shell Interactive scraping console startproject Create new project version Print Scrapy version view Open URL in browser, as seen by Scrapy [ more ] More commands available when run from project directory Use "scrapy <command> -h" to see more info about a command ``` ```python # Check scrapy in python script >>> import scrapy >>> scrapy.version_info (1.5.2) ``` ### Simple Scrapy tutorial 這裡用一個專門練習爬蟲的網站 http://books.toscrape.com/ 上爬取輸資訊, 先分析一下我們想爬的資訊,用 Chrome進入網頁後,可以對任何一個書籍圖示點右鍵後,點選「inspect」「審查元素」, ![](https://i.imgur.com/3YXwFNH.jpg) 網頁最下面的**NEXT**也一樣動作: ![](https://i.imgur.com/1afLG4m.jpg) 發現我們要的書籍資訊在 * < article class="product_pod" > * 書名:h3 > a元素的 **title屬性** * 書價:< p class="price_color">元素的**文字**中 * 下一頁: ul.pager>li.next>a元素的**href**屬性中 以下是最基本爬蟲實現: ```bash # 第一步: # 會產生一個專案,名字是 example (會產生 example資料夾) # 所以開始前可以先cd到你想測試爬蟲的資料夾 $ scrapy startproject example New Scrapy project 'example', using template directory '/home/eric/anaconda3/envs/scrapy/lib/python3.6/site-packages/scrapy/templates/project', created in: /home/eric/coding/python/py_internet/scrapy/example You can start your first spider with: cd example scrapy genspider example example.com #顯示專案資料夾結構 $ tree example example ├── example │   ├── __init__.py │   ├── items.py │   ├── middlewares.py │   ├── pipelines.py │   ├── __pycache__ │   ├── settings.py │   └── spiders │   ├── __init__.py │   └── __pycache__ └── scrapy.cfg # 到你自己喜歡的資料夾 $ cd ./example./example/spiders # 產生一個 python檔來實現爬充 # (這裡用vim, 但你可以用你自己的編輯器) $ vim book_spider.py # .py 檔內容在下一個區塊顯示 # 完成 .py檔後執行 $ scrapy crawl books -o books.csv ``` ```python # book_spider.py # -*- coding: utf-8 -*- import scrapy class BookSpider(scrapy.Spider): # 每個爬蟲唯一標識(就是上面執行指令的 books) name = "books" # 爬蟲起始網址 start_urls = ['http://books.toscrape.com/'] def parse(self, response): # 分析網頁,書資訊在<article > 元素中 # 用 css() 方法去找所有這樣元素 for book in response.css('article.product_pod'): # 書名位置 name = book.xpath('./h3/a/@title').extract_first() # 價錢位置 price = book.css('p.price_color::text').extract_first() yield {'name': name, 'price': price,} # 找 NEXT 下一頁的連結 next_url = response.css('ul.pager li.next a::attr(href)').extract_first() if next_url: next_url = response.urljoin(next_url) yield scrapy.Request(next_url, callback=self.parse) ``` 幾個小結論: 1. 以上顯示 Scrapy已經高度封裝好很多細節 2. **name** 屬性在一個專案下是唯一標識(這裡是 "books") 3. **start_urls** 屬性是每一個爬蟲起始位置 4. **parse** 方法是scrapy回呼解析函數,主要是分析資料(XPath/CSS)和其他連結下載請求