天天看點

exit函數_基本socket函數的解讀--Berkeley socket的重點的翻譯

看了unix網絡程式設計是否有點感覺到它講API講的很雜,更像一本字典而不是一個可以快速學習的書。這裡總結了基礎的socket API并附帶一些例子應該能幫助你更快的學習。

GitHub:helintongh/Web-Server

歡迎點贊

什麼是socket?

  • 套接字是網絡通信路徑的本地端點的抽象表示(句柄)。Berkeley sockets API将其表示為Unix中的一個檔案描述符(檔案句柄),它為資料流的輸入和輸出提供了一個公共接口。
  • 簡單來說:它們是利用标準 UNIX file descriptors(檔案描述符)與其它程式溝通的一種方式。

BSD和POSIX套接字有差别的API

exit函數_基本socket函數的解讀--Berkeley socket的重點的翻譯

所含頭檔案

exit函數_基本socket函數的解讀--Berkeley socket的重點的翻譯

套接字函數總結

exit函數_基本socket函數的解讀--Berkeley socket的重點的翻譯

套接字API通常提供以下功能:

  1. socket()函數建立一個特定類型的套接字(由整數編号辨別),并将系統資源配置設定給它。 -
  2. bind()通常用于伺服器端,并将套接字與套接字位址結構相關聯,即指定的本地IP位址和端口号。
  3. listen()在伺服器端使用,并讓綁定的TCP套接字進入監聽狀态。
  4. connect()在用戶端使用,并将空閑的本地端口号配置設定給套接字。對于TCP套接字,它會嘗試建立新的TCP連接配接。
  5. accept()在伺服器端使用。它接收從遠端客戶機建立的新TCP連接配接的接收傳入請求,并建立與此連接配接的套接字位址相關聯的新套接字。
  6. send(),recv(),sendto()以及recvfrom()用于發送和接收資料。還可以使用标準函數write()和read()。
  7. close() 使系統釋放配置設定給套接字的資源。對于TCP而言作用是終止連接配接。
  8. gethostbyname()和gethostbyaddr() 于解析主機名和位址。僅支援IPv4。
  9. select()用于挂起程式,等待套接字清單中的一個或多個套接字去準備讀/寫或出現錯誤而繼續挂起。
  10. poll() 用于檢查套接字中的套接字的狀态。這個函數可以測試套接字集合,看看是否有套接字可以寫入/讀取或是否發生錯誤。
  11. getsockopt() 用于檢索指定套接字的特定套接字選項的目前值。
  12. setsockopt() 用于為指定的套接字設定特定套接字選項。

socket

#include            

函數socket()建立用于通信的端點,并傳回套接字的檔案描述符。它使用了三個參數:

family指定所建立套接字的協定族。例如:

  • AF_INET用于網絡協定IPv4(僅IPv4)
  • AF_INET6對于IPv6(在某些情況下,向後相容IPv4)
  • AF_UNIX用于本地套接字(使用檔案)

type

  • SOCK_STREAM(可靠的面向流的服務或流套接字)
  • SOCK_DGRAM(資料報服務或資料報套接字,多用于UDP)
  • SOCK_SEQPACKET(可靠的順序分組服務)
  • SOCK_RAW(網絡層上的原始協定)

protocol指定要使用的實際傳輸協定。最常見的是IPPROTO_TCP、IPPROTO_SCTP、IPPROTO_UDP、IPPROTO_DCCP。這些協定在netinet/in.h檔案中指定。值0可用于從標明的域和類型中選擇預設協定。

如果發生錯誤,函數傳回-1。否則,它傳回一個整數,表示新配置設定的描述符。

bind

#include            

bind()将套接字與位址關聯起來。當使用套接字()建立套接字時,隻給它一個協定族,而不給它配置設定位址。在套接字可以接受來自其他主機的連接配接之前,必須執行此關聯。該函數有三個參數: - sockfd,表示套接字的描述符 - my_addr,指向表示要綁定到的位址的sockaddr結構的指針。 - addrlen,類型為socklen_t的字段,指定sockaddr結構的大小。 Bind()成功時傳回0,出錯時傳回-1。

listen

#include            

在套接字與位址關聯之後,listen()為傳入連接配接準備套接字。然而,這隻對面向流的(面向連接配接的)資料模式是必要的,即,用于套接字類型(SOCK_STREAM、SOCK_SEQPACKET)。listen()需要兩個參數: - sockfd,一個有效的套接字描述符。 - backlog,一個整數,表示可以在任何時間排隊的挂起連接配接的數量。作業系統通常對這個值設定一個上限。 一旦連接配接被接受,它就會退出隊列。成功時,傳回0。如果發生錯誤,傳回-1。

accept

#include            

當應用程式偵聽來自其他主機的面向流的連接配接時,它會收到此類事件的通知(cf. select()函數), 并且必須使用accept()函數初始化連接配接。它為每個連接配接建立一個新的套接字,并從監聽隊列中删除連接配接。該函數有以下參數: - sockfd,具有排隊連接配接的監聽套接字的描述符。 - cliaddr,一個指向sockaddr結構的指針,用于接收用戶端的位址資訊。 - addrlen,指向socklen_t位置的指針,該位置指定傳遞給accept()的客戶機位址結構的大小。 當accept()傳回時,這個位置包含結構的大小(以位元組為機關)。

accept()傳回接收連接配接的新套接字描述符,如果發生錯誤,傳回-1。所有與遠端主機的進一步通信現在都通過這個新的套接字進行。資料報套接字不需要accept()處理,因為接收者可以使用監聽套接字立即響應請求。

connect

connect()建立到特定遠端主機的直接通信連接配接,該遠端主機通過套接字(套接字由檔案描述符辨別)的位址辨別。

#include            

connect參數與bind類似 - connect()建立到特定遠端主機的直接通信連接配接,該遠端主機通過套接字(套接字由檔案描述符辨別)的位址辨別。 - 當使用面向連接配接的協定時,這将建立連接配接。某些類型的協定是無連接配接的,尤其是使用者資料報協定。當與無連接配接協定一起使用時,connect定義發送和接收資料的遠端位址,允許使用send和recv等函數。在這些情況下,connect函數阻止接收來自其他源的資料報。 - connect()傳回一個表示錯誤代碼的整數:0表示成功,-1表示錯誤。從曆史上看,在bsd獲得系統中,一個套接字描述符定義的狀态如果電話連接配接失敗(因為它是單一Unix中指定的規範),是以,便攜式應用程式應該立即關閉套接字描述符和獲得一個新的與套接字描述符(),在調用connect()失敗。

C/S使用TCP連接配接的例子

Server

建立一個簡單的TCP伺服器需要以下步驟: 1. 建立一個TCP套接字,并調用套接字()。 2. 使用bind()調用将套接字綁定到偵聽端口。在調用bind()之前,程式員必須聲明一個sockaddr_in結構,清除它(使用memset())和sin_family (AF_INET),并填充它的sin_port(監聽端口,按網絡位元組順序)字段。可以通過調用函數htons() (host to network short)将一個短int轉換為網絡位元組順序。 3. 準備套接字監聽連接配接(使其成為偵聽套接字),并調用listen()。 4. 通過調用accept()接受傳入連接配接。讓伺服器進入阻塞,直到接收到傳入連接配接,然後傳回接受連接配接的套接字描述符。初始描述符仍然是偵聽描述符,并且可以在任何時候使用這個套接字再次調用accept(),直到它關閉為止。 5. 與遠端主機通信,可以通過send()和recv()或write()和read()來完成。 6. 最後,使用close()關閉已打開的每個套接字(一旦不再需要)。

下面的程式在端口号1100上建立一個TCP伺服器:

#include            

Client

編寫TCP客戶機應用程式涉及以下步驟: 1. 建立一個TCP套接字,并調用socket()。 2. 使用connect()連接配接到伺服器,傳遞一個sockaddr_in結構,将sin_family設定為AF_INET,将sin_port設定為端點正在監聽的端口(以網絡位元組順序),并将sin_addr設定為監聽伺服器的IP位址(也以網絡位元組順序)。 3. 通過使用send()和recv()或write()和read()與伺服器通信。 4. 終止連接配接并通過調用close()清理。

#include            

C/S使用UDP連接配接的例子

Server

應用程式可以在端口号7654上設定UDP伺服器,如下所示。程式包含一個無限循環,使用recvfrom()接收UDP資料報。

#include            

Client

一個簡單的用戶端程式,發送一個UDP包,其中包含字元串“Hello World!”發送到位址127.0.0.1和端口号7654:

#include            

繼續閱讀