📘
Beej's Guide to Network Programming 正體中文版
  • 簡介
  • 原著資訊
  • 譯者誌謝
  • 進階資料
  • 簡體中文版
  • 中文授權
  • 聯絡譯者
  • 1. 導讀
    • 1.1. 本書的讀者
    • 1.2. 平台與編譯器
    • 1.3. 官方網頁與書本
    • 1.4. Solaris/SunOS 程式設計師該注意的事
    • 1.5. Windows 程式設計師該注意的事
    • 1.6. 來信原則
    • 1.7. 鏡射站台(Mirroring)
    • 1.8. 譯者該注意的
    • 1.9. 版權與散佈
  • 2. 何謂 Socket
    • 2.1 兩種 Internet Sockets
    • 2.2 底層漫談與網路理論
  • 3. IP address、結構與資料轉換
    • 3.1. IPv4 與 IPv6
      • 3.1.1. Sub network (子網段)
      • 3.1.2. Port Number(連接埠號碼)
    • 3.2. Byte Order(位元組順序)
    • 3.3. 資料結構
    • 3.4. IP 位址,續集
      • 3.4.1 Private Network
  • 4. 從 IPv4 移植為 IPv6
  • 5. System call 或 Bust
    • 5.1. getaddrinfo()-準備開始!
    • 5.2. socket()-取得 File Descriptor!
    • 5.3. bind()- 我在哪個 port?
    • 5.4. connect(),嘿!你好。
    • 5.5. listen()-有人會呼叫我嗎?
    • 5.6. accept()- 謝謝你 call 3490 port
    • 5.7. send() 與 recv()- 寶貝,我們來聊天!
    • 5.8. sendto() 與 recvfrom()- 來點 DGRAM
    • 5.9. close() 與 shutdown()- 你消失吧!
    • 5.10. getpeername()-你是誰?
    • 5.11. gethostname()-我是誰?
  • 6. Client-Server 基礎
    • 6.1. 簡單的 Stream Server
    • 6.2. 簡單的 Stream Client
    • 6.3. Datagram Sockets
  • 7. 進階技術
    • 7.1. Blocking(阻塞)
    • 7.2. select():同步 I/O 多工
    • 7.3. 不完整傳送的後續處理
    • 7.4. Serialization:如何封裝資料
    • 7.5. 資料封裝
    • 7.6. 廣播封包:Hello World!
  • 8. 常見的問題
  • 9. Man 使用手冊
    • 9.1. accept()
    • 9.2. bind()
    • 9.3. connect()
    • 9.4. close()
    • 9.5. getaddrinfo(), freeaddrinfo(), gai_strerror()
    • 9.6. gethostname()
    • 9.7. gethostbyname(), gethostbyaddr()
    • 9.8. getnameinfo()
    • 9.9. getpeername()
    • 9.10. errno
    • 9.11. fcntl()
    • 9.12. htons(), htonl(), ntohs(), ntohl()
    • 9.13. inet_ntoa(), inet_aton(), inet_addr
    • 9.14. inet_ntop(), inet_pton()
    • 9.15. listen()
    • 9.16. perror(), strerror()
    • 9.17. poll()
    • 9.18. recv(), recvfrom()
    • 9.19. select()
    • 9.20. setsockopt(), getsockopt()
    • 9.21. send(), sendto()
    • 9.22. shutdown()
    • 9.23. socket()
    • 9.24. struct sockaddr and pals
  • 10. 參考資料
    • 10.1. 書籍
    • 10.2. 網站參考資料
    • 10.3. RFC
  • 11. 原著誌謝
Powered by GitBook
On this page
Edit on GitHub
  1. 5. System call 或 Bust

5.8. sendto() 與 recvfrom()- 來點 DGRAM

我聽到你說,「這全部都是上等的好貨,可是我該如何使用 unconnected datagram socket 呢?」

沒問題,朋友。我們正要講這件事。

因為 datagram socket 沒有連線到到遠端主機,猜猜看,我們在送出封包以前會需要哪些資訊呢?

對!目的位址!在這裡搶先看:

sendto(int sockfd, const void *msg, int len, unsigned int flags,
       const struct sockaddr *to, socklen_t tolen);

如你所見,這個呼叫基本上與呼叫 send() 一樣,只是多了兩個額外的資訊。to 是一個指向 struct sockaddr(這或許是另一個你可以在最後轉型的 struct sockaddr_in 或 struct sockaddr_in6 或 struct sockaddr_storage)的指標,它包含了目的 IP address 與 port。tolen 是一個 int,可以單純地將它設定為 sizeof *to 或 sizeof(struct sockaddr_storage)。

為了能自動處理目的位址結構(destination address structure),你或許可以用底下的 getaddrinfo() 或 recvfrom(),或者你也可以手動填上。

如同 send(),sendto() 會傳回實際已傳送的資料數量(一樣,可能會少於你要傳送的資料量!)而錯誤時傳回 -1。

recv() 與 recvfrom() 也是差不多的。recvfrom() 的對照如下:

int recvfrom(int sockfd, void *buf, int len, unsigned int flags,
            struct sockaddr *from, int *fromlen);

一樣,它跟 recv() 很像,只是多了兩個欄位。from 是指向 local struct sockaddr_storage 的指標,這個資料結構包含了封包來源的 IP address 與 port。fromlen 是指向 local int 的指標,應該要初始化為 sizeof *from 或是 sizeof(struct sockaddr_storage)。當函式傳回時,fromlen 會包含實際上儲存於 from 中的位址長度。

recvfrom() 傳回接收的資料數目,或在發生錯誤時傳回 -1[並設定相對的 errno]。

所以這裡有個問題:為什麼我們要用 struct sockaddr_storage 做為 socket 的型別呢?為什麼不用 struct sockaddr_in 呢?

因為你知道的,我們不想要讓自己綁在 IPv4 或 IPv6,所以我們使用通用的泛型 struct sockaddr_storage,我們知道這樣有足夠的空間可以用在 IPv4 與 IPv6。

(所以 ... 這裡有另一個問題:為什麼不是 struct sockaddr 本身就可以容納任何位址呢?我們甚至可以將通用的 struct sockaddr_storage 轉型為通用的 struct sockaddr!似乎沒什麼關係又很累贅啊。答案是,它就是不夠大,我猜在這個時候更動它會有問題,所以他們就弄了一個新的。)

記住,如果你 connect() 到一個 datagram socket,你可以在你全部的交易中只使用 send() 與 recv()。socket 本身仍然是 datagram socket,而封包仍然使用 UDP,但是 socket interface 會自動幫你增加目的與來源資訊。

Previous5.7. send() 與 recv()- 寶貝,我們來聊天!Next5.9. close() 與 shutdown()- 你消失吧!

Last updated 2 years ago