Linux網路程式設計:socket程式設計簡介、網路位元組序及相關函式
Socket(套接字)
socket可以看成是使用者程序與核心網路協議棧的程式設計介面(API函式)。
socket不僅可以用於本機的程序間通訊,還可以用於網路上不同主機的程序間通訊。
IPv4套接字地址結構
IPv4套接字地址結構通常也稱為“網際套接字地址結構”,它以“sockaddr_in”命名,
定義在標頭檔案netinet/in.h中。(可以在Linux上用命令man 7 ip檢視其結構)
struct sockaddr_in {
uint8_t sin_len;
sa_family_t sin_family;
in _port_t sin_port;
struct in_addr sin_addr;
char sin_zero[8];
};
sin_len:整個sockaddr_in結構體的長度,在4.3BSD-Reno版本之前的第一個成員是sin_family
sin_family:指定該地址家族,對於IPv4來說必須設為AF_INET(Socket不僅可以用於TCP/IP還可以用於UNIX域協議)
sin_port:埠
sin_addr:IP地址
sin_zero:暫不使用,一般將其設定為0
通用套接字地址結構
通用地址結構用來指定與套接字關聯的地址(可以支援其他協議)。從應用程式開發人員的觀點看,它的唯一用途就是對指向特定於協議的套接字地址結構的指標執行強制轉換。
struct sockaddr {
uint8_t sin_len;
sa_family_t sin_family;
char sa_data[14];
};
sin_len:整個sockaddr結構體的長度
sin_family:指定該地址家族
sa_data:由sin_family決定它的形式
網路位元組序
大端位元組序:
最高有效位(MSB:Most Significant Bit)儲存於最低記憶體地址處,最低有效位(LSB:Lowest Significant Bit)儲存於最高記憶體地址處。
小端位元組序:
最高有效位(MSB:Most Significant Bit)儲存於最高記憶體地址處,最低有效位(LSB:Lowest Significant Bit)儲存於最低記憶體地址處。
(這兩種位元組序之間沒有標準可言,兩種格式都有系統使用)
主機位元組序:
不同的主機有不同的位元組序,如x86為小端位元組序,Motorola 6800為大端位元組序,ARM位元組序是可配置的。
網路位元組序:
網路位元組序規定為大端位元組序。
//測試我們的電腦主機位元組序是大端位元組序還是小端位元組序
#include<stdio.h>
#include<arpa/inet.h>
int main(void)
{
unsigned int x = 0x12345678;
unsigned char *p = (unsigned char *)&x;
printf("%x %x %x %x\n", p[0], p[1], p[2], p[3]);//若本機是小端位元組序則輸出78 56 34 12
unsigned int y = htonl(x);//呼叫htonl()轉換為網路位元組序
p = (unsigned char *)&y;
printf("%x %x %x %x\n", p[0], p[1], p[2], p[3]);//網路位元組序規定為大端位元組序,所以輸出12 34 56 78
return 0;
}
為使網路程式具有可移植性,使同樣的程式碼在大端和小端計算機上編譯後都能正常執行,可呼叫以下庫函式做網路位元組序和主機位元組序的轉換。
//h表示host,n表示network,l表示32位長整數,s表示16位短整數
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
地址轉換函式(用於IP地址轉換)
地址轉換函式用於點分十進位制數串(如”206.168.112.96”)和網路位元組序的二進位制值(這是存放在套接字地址結構中的值)之間轉換網際地址。
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);
char *inet_ntoa(struct in_addr in);
//實戰
//該程式輸出結果: add=3232235620 192.168.0.100
#include<stdio.h>
#include<arpa/inet.h>
int main(void)
{
unsigned int addr = inet_addr("192.168.0.100"); //轉換後是網路位元組序(大端)
printf("add=%u\n", ntohl(addr));//在列印之前需將addr轉化為主機位元組序
struct in_addr ipaddr;
ipaddr.s_addr = addr;
printf("%s\n", inet_ntoa(ipaddr));
return 0;
}
套接字型別
1)流式套接字(SOCK_STREAM)
提供面向連線的、可靠的資料傳輸服務,資料無差錯,無重複的傳送,且按傳送順序接收,對應TCP協議。
2)資料報式套接字(SOCK_DGRAM)
提供無連線服務。不提供無錯保證,資料可能丟失或重複,並且接收順序混亂, 對應UDP協議。
3)原始套接字(SOCK_RAW)
使我們可以跨越傳輸層直接對IP層進行封裝傳輸。(應用層直接和IP層)