套接字是通信端點的抽象。與應用程序要使用文件描述符訪問文件一樣,訪問套接字也需要套接字描述符。套接字描述符在UNIX系統是用文件描述符實現的。事實上,許多處理文件描述符的函數(如read和write)都可以處理套接字描述符。
要創建一個套接字,可以調用socket函數。
#include <sys/socket.h>int socket(int domain, int type, int PRotocol);返回值:若成功則返回文件(套接字)描述符,若出錯則返回-1
參數domain(域)確定通信的特性,包括地址格式。表16-1總結了由POSIX.1指定的各個域。各個域有自己的格式表示地址,而表示各個域的常數都以AF_開頭,意指地址族(address family)。
表16-1 套接字通信域
多數系統還會定義AF_LOCAL域,這是AF_UNIX的別名。AF_UNSPEC域可以代表任何域。歷史上,有些平臺支持其他網絡協議(如AF_IPX為NetWare協議族),但這些協議的域常數沒有在POSIX.1標準中定義。
參數type確定套接字的類型,進一步確定通信特征。表16-2總結了由POSIX.1定義的套接字類型,但在實現中可以自由增加對其他類型的支持。
表16-2 套接字類型
參數protocol通常是0,表示按給定的域和套接字類型選擇默認協議。當對同一域和套接字類型支持多個協議時,可以使用protocol參數選擇一個特定協議。在AF_INET通信域中套接字類型SOCK_STREAM的默認協議是TCP(傳輸控制協議)。在AF_INET通信域中套接字類型SOCK_DGRAM的默認協議是UDP(用戶數據報協議)。下表(摘自apue第3版)列出了為因特網域套接字定義的協議:
對于數據報(SOCK_DGRAM)接口,與對方通信時是不需要邏輯連接的。只需要送出一個報文,其地址是一個對方進程所使用的套接字。
因此數據報提供了一個無連接的服務。另一方面,字節流(SOCK_STREAM)要求在交換數據之前,在本地套接字和與之通信的遠程套接字之間建立一個邏輯連接。
數據報是一種自包含報文。發送數據報近似于給某人郵寄信件。可以郵寄很多信,但不能保證投遞的次序,并且可能有些信件丟失在路上。每封信件包含接收者的地址,使這封信件獨立于所有其他信件。每封信件可能送達不同的接收者。
相比之下,使用面向連接的協議通常就像與對方打電話。首先,需要通過電話建立一個連接,連接建立好之后,彼此能雙向地通信。每個連接是端到端的通信信道。會話中不包含地址信息,就像呼叫的兩端存在一個點對點的虛擬連接,并且連接本身暗含特定的源和目的地。
對于SOCK_STREAM套接字,應用程序意識不到報文界限,因為套接字提供的是字節流服務。這意味著當從套接字讀出數據時,它也許不會返回所有由發送者進程所寫的字節數。最終可以獲得發送過來的所有數據,但也許要通過若干次函數調用得到。
SOCK_SEQPACKET套接字和SOCK_STREAM套接字很類似,但從該套接字得到的是基于報文的服務而不是字節流服務。這意味著從SOCK_SEQPACKET套接字接收的數據量與對方發送的一致。流控制傳輸協議(Stream Control Transimission Portocol, SCTP)提供了因特網域上的順序數據包服務。
SOCK_RAW套接字提供一個數據報接口用于直接訪問下面的網絡層(在因特網域中為IP)。使用這個接口時,應用程序負責構造自己的協議首部,這是因為傳輸協議(TCP和UDP等)被繞過了。當創建一個原始套接字時需要有超級用戶特權,用以防止惡意程序繞過內建安全機制來創建報文。
調用socket與調用open相類似。在兩種情況下,均可獲得用于輸入/輸出的文件描述符。當不再需要該文件描述符時,調用close來關閉對文件或套接字的訪問,并且釋放該描述符以便重新使用。
雖然套接字描述符本質上是一個文件描述符,但不是所有參數為文件描述符的函數都可以接受套接字描述符。表16-3總結了到目前為止所討論的大多數使用文件描述符的函數處理套接字描述符時的行為。未規定的和由實現定義的行為通常意味著函數不能處理套接字描述符。例如,lseek不處理套接字,因為套接字不支持文件偏移量的概念。
表16-3 使用文件描述符的函數處理套接字時的行為
套接字通信是雙向的??梢圆捎煤瘮祍hutdown來禁止套接字上的輸入/輸出。
#include <sys/socket.h>int shutdown(int sockfd, int how);返回值:若成功則返回0,出錯則返回-1
如果how是SHUT_RD(關閉讀端),那么無法從套接字讀取數據;如果how是SHUT_WR(關閉寫端),那么無法使用套接字發送數據;使用SHUT_RDWR則將同時無法讀取和發送數據。
能夠使用close關閉套接字,為何還要使用shutdown呢?理由如下:首先,close只有在最后一個活動引用被關閉時才釋放網絡端點。這意味著如果復制一個套接字(例如采用dup),套接字直到關閉了最后一個引用它的文件描述符之后才會被釋放。而shutdown允許使一個套接字處于不活動狀態,無論引用它的文件描述符數目多少。其次,有時只關閉套接字雙向傳輸中的一個方向會很方便。例如,如果想讓所通信的進程能夠確定數據發送何時結束,可以關閉該套接字的寫端,然而通過該套接字讀端仍可以繼續接收數據。
本篇博文內容摘自《UNIX環境高級編程》(第2版),僅作個人學習記錄所用。關于本書可參考:http://www.apuebook.com/。
新聞熱點
疑難解答