zoanana990
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    --- tags: CSAPP --- # Chapter 11: Network Programming [課程錄影 Part I](https://www.youtube.com/watch?v=OynSMXfNtiM&list=PLcQU3vbfgCc9sVAiHf5761UUApjZ3ZD3x&index=22&ab_channel=RobbieZhou) / [課程錄影 Part II]() 這裡部會講述太難的網路概念,僅說明一個系統軟體工程師對於網路所需要的基本概念 [TOC] ## 網路基本概念 ![](https://i.imgur.com/61UEhHV.png) > 一切的概念都是從 `client-server` 開始的 舉例來說:現在你想在亞馬遜上買東西 1. 你想點進去看一個商品 2. 亞馬遜收到你要看的需求 3. 亞馬遜提供那個商品的資料給你,透過網頁顯示的方式 4. 你決定下一步你要怎麼做,可能是加入購物車、看其他商品等 當然,你也可以同時是客戶端與服務器,例如:你現在打電話給別人 ![](https://i.imgur.com/4xf49gi.png) 對於網路,電腦將他視為 `I/O` 對應硬碟,從網路獲取的資料經過`I/O` 和內存總線(BUS)複製到內存;相反的,也可以從內存將資料複製到網路。這個概念適用於目前常見的作業系統,例如:windows, macOS, UNIX... ![](https://i.imgur.com/UuyCpdO.png) :::info 這邊我們如果是用 "internet" 代表描述一般的網路概念;"Internet"則是描述一種具體的實現手法,例如通訊協定等等 ::: ![](https://i.imgur.com/NNHZQXE.png) - 這邊介紹最低階的網路(LAN, Local Area Network),利用集線器(Hub)將主機相連。利用集線器的端口,可以將接收到的資訊複製到其他端口上 - 這種網路結構通常出現在校園或同一棟建築物內 - 每個乙太網路適配器都有一個實體位置(MAC address, Media Access Control address),他是48位元組(bit) - 例如:`46:85:fd:b3:3b:f2` - 但是因為集線器成本太高,目前都換成路由器(Routers) - 任何一個主機都可以發送資料給其他主機,其資料名為幀(Frame),每一個幀都有固定位元的頭(header)及有效載荷(Payload)。頭(header)是用來看這一幀的目的與長度,有效載荷是存放資料用的 > Hosts send bits to any other host in chunks called frames ![](https://i.imgur.com/Fjsgaen.png) - 多個乙太網路可以連接成更大的乙太網路,透過網橋(Bridge)來連接,往橋間傳輸的數據線速度與一般的路由器不同,往橋和往橋間的帶寬是 1Gb/s,一般的主機與路由器的帶寬是 100Mb/s。 - 利用網橋可以將網路的範圍擴大 ![](https://i.imgur.com/VyIlc9c.png) 我們可以將區域網路簡化成上圖,可以想像成一堆主機在對話 ![](https://i.imgur.com/qosqld0.png) - 網路則是很多個地方網路(LAN)透過路由器連接起來,而路由器之間就會有通訊協定,通訊協定就是不同的地區網路用同一種語言溝通 - 上面這張投影片中,`LAN1`和`LAN2`是不同的區域網路,因此這兩種網域的溝通就要經過協調,也就是通訊協定 ![](https://i.imgur.com/4MBEozc.png) 現實生活中也是利用這些概念進行,只是範圍擴大到全世界,這種網路稱為廣域網路(Wide Area Network, WAN) ![](https://i.imgur.com/9UrhgGL.png) - 要怎麼在這些不同的網域傳輸資料呢? - 首先定義一個通訊協定,他是用來規範主機與路由器在各個網域之間傳輸資料的方式 - 這個通訊協定可以將不同網域的差異變小 ![](https://i.imgur.com/O6Y6yCt.png) - 通訊協定是用來做什麼的呢? - 定義命名方式 - 當我們要寄信時,我們必須說出地址,而地址就會有規範,這樣郵差才可以把信送到你想寄的地方 - 然而這種規範在剛開始執行時並不順利,因為網路在傳輸時就像寄信一樣,也有信件的大小限制。剛開始執行時,一個封包大約限制在2000位元組,因此如果有很長的資訊,必須拆成很多個封包寄送 - 但是電話不是,電話有專門的線路,而電信公司也會負責這點,確保你打電話時可以保持通訊,不會有人打擾 - 定義傳輸方式 - 定義一個封包(packet)的標準單位 - 這個資料包必須包含頭部(header)和有效載荷(Payload) - 頭部(header):包含這個封包的大小、來源地及目的地 - 有效載荷(Payload):這個封包的資料 ![](https://i.imgur.com/6ZzCTrp.png) 這張投影片介紹傳輸資料的8個基本步驟: 1. 主機A將資料及主機B的虛擬地址複製到記憶體(內存)中 2. 將資料包在網路的封包內,此時網路封包的有效載荷(Payload)為要傳遞的資訊,封包頭部(Packet Header, PH)為傳輸目的地的地址。再將這個封包裝在地區網路的幀內,此時幀的頭部(Frame Header)為路由器的地址,幀的有效載荷(Payload)為整個網路封包 - 先將幀從主機A封裝後送到協議軟體,再將幀送到LAN1上 | data| Packet Header(PH) | Frame Header(FH) | | -------- | -------- | -------- | |Frame Payload|Frame Payload| Frame Header| 3. 從LAN1將幀複製到網路上(區域網路中,==由主機A&rarr;路由器==) 4. 當幀到達路由器時,路由器的LAN1適配器會讀取他,並將其送到協議軟體內 5. 路由器從PH找到目的地,並將他送到該網域的適配器。 - 此時路由器會將LAN1的FH消除,加上LAN2的FH 6. 路由器的LAN2適配器複製幀到網路上(區域網路,==由路由器&rarr;主機B==) 7. 當幀到達主機時,適配器到從電纜中讀取,並將他送到協議軟體內 8. 剝落PH, FH取得資料 > 將頭部加上去的動作就叫做封裝 ![](https://i.imgur.com/VQwg3HA.png) :::success 延伸問題: 1. 路由器怎知道要轉發到哪 2. 網路拓樸變化時,怎麼通知路由器 3. 封包會不會丟失 ::: ![](https://i.imgur.com/LcoTDUz.png) - 常用的網路協定包含以下三種:`IP`、`UDP`及`TCP` - IP(Internet Protocol) - 定義主機的命名方式 - 定義怎麼傳送封包(Packet, Datagram) - 資料丟失的現象:數據線過熱,如果數據丟失,IP層不會試圖恢復,因此這一層的傳輸不是可靠的 - ==主機對主機()== - UDP(Unreliable Datagram Protocol) - 這層比IP層還要高一點 - 這裡可以傳輸電腦遊戲(線上遊戲),就是沒有傳到也不會怎麼樣 - TCP(Transmission Control Protocol) - 百分之99都是使用這個TCP進行傳輸,他也在IP層之上 - TCP提供一個和電話一樣穩定通訊的方式,他會將資料分為很多個封包,如果對方沒有收到資料,就會重複發到接收為止 - 使用 `socket` 介面寫程式 ![](https://i.imgur.com/xIkNqId.png) 這邊可以看到,可以利用 `socket` 從 `User Mode` 就可以進行資料傳輸 ![](https://i.imgur.com/EIbVQxX.png) - `IP address`:由四個十進位的數字用點連起來,這四個數字只能從0~255 - `IP address`用十進位表示,但是我們也可以使用16進位表示他 - 這邊需要注意,`IP address`是`Big Endian`,而一般的作業系統都是使用`Little Endian` - 利用`IP address`可以知道你在用哪個網域,例如`128.2`就是CMU的`IP address` ![](https://i.imgur.com/7s3Hui5.png) - 因為`IPv4` 是 32 位元的地址,但是世界太多人了,地址可能不夠用,因此有了`IPv6`,也就是128位元的地址 - 但是到了現在,儘管`IPv6`已經出現了15年,人類已經找出如何用`IPv4`的表示很多地址,因此`IPv6`還是很少人用 ![](https://i.imgur.com/lfTkhXv.png) - `IP address` 需要將 `Big Endian`轉換成 `Little Endian`,這邊可以使用標準函式庫 ![](https://i.imgur.com/qFfslDT.png) - 剛剛談到, `IP Address` 是用四個十進位表示,而他也可以轉換成16進位,這時利用標準函式庫即可得到 - `0x8002C2F2 = 128.2.194.242` ![](https://i.imgur.com/bkCgWIw.png) - 今天我們使用 `GOOGLE` ,我們不會使用他的IP,相反的我會使用網址,`www.google.com` - 我們也都知道,`.com`是指商業公司、`.edu`是指教育機構等等,當然不同的地區也會有不同的後綴,例如`.de`代表德國、`.us`代表美國等等 - 但是機器並不認得這些網址,因此會有一個字典找到`IP`與網域間的關係,也就是 `Domain Naming System(DNS)` ![](https://i.imgur.com/IxAxTRt.png) - 不用把 `DNS` 養得太複雜,他其實就是一個映射函數,也就是給他網域名稱,他就給你 `IP` 地址,反之亦然 ![](https://i.imgur.com/YjYNDN6.png) ![](https://i.imgur.com/dZBCOUb.png) ![](https://i.imgur.com/1oSSbTF.png) - 這邊我們可以利用系統,給予電腦網域名稱就可以讓他給我 `IP` 地址 - 這邊我們做個實驗 ```shell= $ nslookup www.cs.cmu.edu Server: 127.0.0.53 Address: 127.0.0.53#53 Non-authoritative answer: www.cs.cmu.edu canonical name = scs-web-lb.andrew.cmu.edu. Name: scs-web-lb.andrew.cmu.edu Address: 128.2.42.95 ``` - 如果我們給予一個不存在的網域,則會返回沒有回應 ```shell= Not find www.cs.standford.edu: No answer ``` - 但是網域名稱與`IP`並不是一一對應的,是==多對多映射的== ```shell= Name: twitter.com Address: 104.244.42.65 Name: twitter.com Address: 104.244.42.129 ``` - 這邊也可以看到,如果我們想要到同一個網域,他可能會給我們不同地址,這些地址都在變化 - `IP`地址的分配分為兩種,一種是靜態分配,這種地址不會變;另外一種是動態分配,這種地址可能是一段時間之內分配給你的 ![](https://i.imgur.com/IPGla3N.png) - 目前主流的連接方式是透過`TCP`,它可以使兩台主機進行連接,而且類似電話依樣不會有數據突然消失的問題 - `socket` 包含一個`IP`地址和一個端口,端口號是16個位元組 - 一個機器有很多服務,而不同端口號可以對應到不同服務 - 臨時端口(Ephemeral Port):客戶端的端口是由客戶端核心分配的 - 知名端口(Well-Known Port) ![](https://i.imgur.com/FQZ8dP2.png) 目前比較熱門的服務器都會指派這些知名端口(Well-Known Ports)進行,如上 ![](https://i.imgur.com/wFWRlWW.png) 假設現在連線開始,客戶端視使用臨時接口,要求連接伺服器第80號接口 ![](https://i.imgur.com/K9m8wni.png) 伺服器第80號接口是網路服務,如果想要使用其他服務的話需要連接其他端口,而這些端口是獨立的不會互相影響 ![](https://i.imgur.com/6KdAWMV.png) Socket Interface(台譯:插座介面、陸譯:套接字接口) - 對於核心來說,`socket`是一個連線的終點 - 對於應用程式來說,`socket`就像是硬碟一樣,只是對象不是電腦中的硬體而是網路 ![](https://i.imgur.com/GqlARkC.png) ## `socket API` 套接字接口 前兩的字節(Bytes)是描述這個`socket`是甚麼類型的? 例如:`TCP`、`IPv6`、`UDP` ![](https://i.imgur.com/KJrfyK8.png) 本圖的左邊是客戶端、右邊是伺服器端 - 前置動作 - 客戶端:先搞清楚目的地在哪、想要什麼服務 - 伺服器端: - 客戶端連接伺服器端,接收之後開始資料傳輸 - 這邊的函數加上`roi`代表 reliable i/o - 如果客戶端掉線了 - 伺服器端也會取消客戶端的連接 以 linux 核心的角度來說,一個套接字就是通信的一個端點,以程式碼的角度來說,套接字就是一個文件 ```c= struct sockaddr_in{ uint16_t sin_family; /* Protocol Family (Always AF_INET) */ uint16_t sin_port; /* Port number in network byte order */ struct in_addr sin_addr; /* IP Address */ unsigned char sin_zero[8]; }; struct sockaddr{ uint16_t sa_family; char sa_data[14]; }; ``` --- ### `socket` 常用函式 - `socket` 函式 (套接字描述符) ```c int socket(int domain, int type, int protocol); ``` 如果想將 `socket` 變成一個端點,可以用編碼的參數調用: ```c clientfd = Socket(AF_INET, SOCK_STREAM, 0); // AF_INET: 使用32位元的IP地址 // SOCK_STREAM: socket連接的一的端點 ``` - 最好是使用 `getaddrinfo` 來自動生成這些參數 - `socket` 的 `clientfd` 是部分打開的,還不能用於讀寫。如何打開套接字的工作取決於我們是客戶端還是服務器。 - 客戶端的函數 - `connect` 函式 ```c int connect(int clientfd, const struct sockaddr *addr, socklen_t addrlen); ``` `connect` 函數是將客戶端和伺服器連接,啟動連接後,`connect` 會停止一陣子,直到確定連接伺服器或是連接失敗才會繼續動作 如果成功,`clientfd` 描述現在就準備好可以讀寫了,得到的連接是socket字對 ``` (x:y, addr.sin_addr:addr.sin_port) ``` 其中 `x`, `y` 分別對應客戶端的地址與端口,它唯一確定了客戶端主機上的客戶端進程。對於socket最好的方式是用 `getaddrinfo` 來未connect提供參數 - 伺服器的函數 - `bind` 函式 ```c int bind(int sockfd, const struct *addr, socklen_t addrlen); ``` bind函數告訴系統核心將 `addr` 中的伺服器套接字 (socket) 地址和套接字描述符 `sockfd` 連接起來 - `listen` 函式 - ==客戶端是發起連接的主動實體、服務氣勢等待客戶端連接請求被動實體== - listen 函數是將 sockfd 轉換成 listening socket,這個 socket 可以接受客戶端的連線請求 - `accept` 函式 ```c int accept(int listenfd, struct sockaddr *addr, int *addrlen); ``` - `accept` 等待來自可護端的連線請求到達偵聽描述符 listenfd,然後在 addr中填寫客戶端的套接字地址,返回一個已連接描述符(Connected Descriptor) - 過程如下: - 第一步、服務器調用 accept,等待連接請求到達監聽描述符 listenfd,此時設定描述符為 3 - 第二步、客戶端調用 connect 函式,發送請求到 listenfd - 第三步、accept 打開一個新的已連接描述符 connfd,描述符為 4,在 clientfd 和 connfd 建立連線,最後返回 connfd 給應用程式,流程如下圖所示 ![](https://i.imgur.com/IiLLmeZ.png) :::info 為什麼要分為監聽描述符和已連接描述符? 因為在並行 (Concurrency) 的服務器中,監聽描述符可以一次處理很多客戶端的連接,每次請求一個連接時,監聽描述符都可以 fork 初一個新的行程,使得已連接描述符可以與之連接。 ::: - 主機和伺服器的轉換函數 - getaddrinfo 函式 將相應的主機名稱、主機地址、服務器名稱和字串符號轉換成套接字地址結構 ```c #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> int getaddrinfo(const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **results); void freeaddrinfo(struct addrinfo *result); ``` ![](https://i.imgur.com/yoq8Ddx.png) 在客戶端調用 getaddrinfo 之後會一次走訪這個資料結構中的地址,直到調用 socket 和 connect 成功;相似的、主機則是會走訪這個資料結構中的地址,直到 socket 和 bind 成功。 - getnameinfo 函式 與 getaddrinfo 相反,他是將套接字地址結構轉回相應的主機與服務器的字串 - 套接字接口的輔助函式 - open_clientfd 函式 - open_listenfd 函式 - echo 客戶端和服務器的示例 ## Web 服務器 - Web 基礎 - Web 內容 - HTTP 事務 - 服務動態內容 ## Tiny Web 服務器

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully