sock( ) bind( ) connect( )


Linux下的socket()函數

調用頭文件<sys/socket.h>中的socket函數

int socket(int af, int type, int protocol);

 

1)af為地址族(address Family),IP地址的類型,常用的有 AF_INET和 AF_INET6。

  AF_INET表示IPv4地址,如127.0.0.1(特殊的IP地址,表示本機地址)

  AF_INET6是IPvl6地址

也可以使用PF前綴,PF是“Protocol Family” 的簡寫,和AF是一樣的。

PF_INET 等價於 AF_INET,PF_INET6 等價於 AF_INET6

 

2)type為數據傳輸方式/套接字類型,常用有SOCK_STREAM(流格式套接字/面向連接的套接字)和

SOCK_DGRAM( 數據報套接字/無連接的套接字)

3)protocol表示傳輸協議,常用的有IPPROTO_TCP和IPPROTO_UDP

 

創建TCP套接字

int tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  //IPPROTO_TCP表示TCP協議

 

創建UDP套接字

int udp_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);  //IPPROTO_UDP表示UDP協議

上面兩種情況都只有一種協議滿足條件,可以將 protocol 的值設為 0,系統會自動推演出應該使用什么協議,如下所示:

int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);  //創建TCP套接字
int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);  //創建UDP套接字

 

四、bind()和connect()函數:綁定套接字並創建連接

socket() 函數用來創建套接字,確定套接字的各種屬性,然后服務器端要用 bind() 函數將套接字與特定的 IP 地址和端口綁定起來,只有這樣,流經該 IP 地址和端口的數據才能交給套接字處理。類似地,客戶端也要用 connect() 函數建立連接。

bind()函數

int bind(int sock, struct sockaddr *addr, socklen_t addrlen);  //Linux

 

sock為socket文件描述符

addr為sockaddr結構體變量的指針

addrlen為addr變量的大小,可由sizeof()算出

舉個栗子:

//創建套接字
int serv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

//創建sockaddr_in結構體變量
struct sockaddr_in serv_addr; memset(&serv_addr, 0, sizeof(serv_addr)); //計算serv_addr的長度,並用0填充,返回地址 serv_addr.sin_family = AF_INET; //使用IPv4地址 serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //具體的IP地址 serv_addr.sin_port = htons(1234); //端口 //將套接字和IP、端口綁定 bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr));//先使用sockaddr_in的變量
在,強制類型轉化為sockaddr類型

 

sockaddr_in結構體如下

struct sockaddr_in{
    sa_family_t     sin_family;   //地址族(Address Family),也就是地址類型
    uint16_t        sin_port;     //16位的端口號
    struct in_addr  sin_addr;     //32位IP地址
    char            sin_zero[8];  //不使用,一般用0填充
};
1) sin_family 和 socket() 的第一個參數的含義相同,取值也要保持一致。

2) sin_prot 為端口號。uint16_t 的長度為兩個字節,理論上端口號的取值范圍為 0~65536,
但 0~1023 的端口一般由系統分配給特定的服務程序,例如 Web 服務的端口號為 80,FTP 服務
的端口號為 21,所以我們的程序要盡量在 1024~65536 之間分配端口號。端口號需要用 htons()
函數轉換 3) sin_addr 是 struct in_addr 結構體類型的變量,下面會詳細講解。 4) sin_zero[8] 是多余的8個字節,沒有用,一般使用 memset() 函數填充為 0。上面的代碼中,
先用 memset() 將結構體的全部字節填充為 0,再給前3個成員賦值,剩下的 sin_zero 自然就是
0 了。

 

 

in_addr 結構體

struct in_addr{
    in_addr_t  s_addr;  //32位的IP地址
};

in_addr_t 在頭文件 <netinet/in.h> 中定義,等價於 unsigned long,長度為4個字節。也就是說,s_addr 是一個整數,而IP地址是一個字符串,所以需要 inet_addr() 函數進行轉換,例如:

unsigned long ip = inet_addr("127.0.0.1");
printf("%ld\n", ip);

輸出:16777343

 

圖解:

 

 為什么使用sockaddr_in而不是sockaddr?

 

sockaddr 是一種通用的結構體,可以用來保存多種類型的IP地址和端口號,而 sockaddr_in 是專門用來保存 IPv4 地址的結構體。另外還有 sockaddr_in6,用來保存 IPv6 地址,它的定義如下:

struct sockaddr_in6 { 
    sa_family_t sin6_family;  //(2)地址類型,取值為AF_INET6
    in_port_t sin6_port;  //(2)16位端口號
    uint32_t sin6_flowinfo;  //(4)IPv6流信息
    struct in6_addr sin6_addr;  //(4)具體的IPv6地址
    uint32_t sin6_scope_id;  //(4)接口范圍ID
};

 

 正是由於通用結構體 sockaddr 使用不便,才針對不同的地址類型定義了不同的結構體。

 

 

connect() 函數

connect() 函數用來建立連接,它的原型為:

參數和bind相同

int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);  //Linux

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM