問題:網路程式設計介面中一些引數的意義是什麼?
sock = socket(PF_INET, SOCK_STREAM, 0);
socket 引數詳解
int socket(int domain, int type, int protocal);
引數 | 意義 |
domain | 套接字中使用的協議族資訊 |
type | 套接字資料傳輸型別資訊 |
prorocol | 裝置間通訊使用的協議資訊 |
socket() 中的 domain 引數(協議族)
- PF_INET → IPv4 網際網路協議族
- PF_INET6 → IPv6 網際網路協議族
- PF_LOCAL → 本地通訊的協議族
- PF_PACKET → 底層資料收發協議
- PF_IPX → Novell 專用協議(網際網路分組交換協議)
- ...
注意:不同協議中的地址表現形式可能不同,網路程式設計時地址型別必須和協議型別匹配
socket() 中的 type 和 protocol 引數
type : 用於指定協議型別
- SOCK_STREAM : 流式資料 (TCP)
- SOCK_UGRAM : 報文式資料(UDP)
protocol :用於指定協議族符合型別的具體協議
- domain 和 type 幾乎可以唯一確定一種協議,因此,這個引數通常為 0
- 即:0 代表 domain 和 type 指定後的預設協議
關於埠號和 IP 地址
- 埠號是一個 2 位元組資料(無符號)
- 0 - 1024 作為特定埠被預定義(分配給特定應用程式)
- IP 地址是一個 4 位元組無符號地址族 (可分為 5 類地址)
深入解析 IP 地址
IP 地址分為 網路標識 和 主機標識 兩部分
- 網路標識:標識網路主機(裝置)所在的網路
- 主機標識:標識網路主機(裝置)的具體地址
問題:一個 IP 地址就 4 個位元組,那麼如何區分網路標識和主機標識呢?
- IP 地址 和 子網掩碼 配合使用區分 網路標識 和 主機標識
- 子網掩碼的表現形式也是一個 4 位元組的整型數(無符號)
- 子網掩碼用於從 IP 地址中提取 網路標識 (& 操作)
深入理解子網掩碼
設:子網掩碼為 M.N.P.Q,則子網可用 IP 地址數量 n = (256 - M) * (256 - N) * (256 - P) * (256 - Q)
例:IP 地址 211.99.34.33,掩碼 255.255.2555.248,因此:211.99.34.33 所在子網有 8 個 IP 地址
所在子網地址: 211.99.34.32
廣播地址:211.99.34.39
6個可分配地址:211.99.34.33 ... 211.99.34.38
注:子網地址即為網路標識
ip 地址 211.99.34.33, 掩碼 255.255.225.248
可知 211.99.34.33 所在子網有 8 個 IP 地址, 且 8 = 2^3(二的三次方),所以 Y = 32 - 3 = 29
可表示為 211.99.34.33 / 29 【簡寫形式】
注:29 為32位子網掩碼的高位
算一算
IP 地址 192.168.3.44,掩碼 255.255.255.0
問:
子網地址是什麼?廣播地址是什麼?可用地址有多少?簡潔表示法是什麼?
答:
子網地址:192.168.3.44
廣播地址:192.168.3.255
可用地址:254 [256 - 0(子網地址) - 255(廣播地址)]
簡潔表示:192.168.3.44 / 24
特殊的地址
- 0.0.0.0 / 0 - 保留,常用於代表 “預設網路”
- 127.0.0.0 / 8 - 迴環地址,常用於本地軟體會送測試
- 255.255.255.255 / 32 - 廣播地址
網路程式設計中的地址型別
int sock = 0;
struct sockaddr_in addr = {0};
sock = socket(PF_INET, SOCK_STREAM, 0); // Protocol Family,協議族
if (sock == -1) {
pritnf("socket error\n");
return;
}
addr.sin_family = AF_INET; // Address Family,地址族
addr.sin_addr.s_addr = inet_addr("192.168.3.241");
addr.sin_addr.port = htons(8899);
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
printf("connect error\n");
return -1;
}
問:(struct sockaddr*)&addr
的強制型別轉換不會出問題嗎?
地址資料型別解析
- struct sockaddr 可理解為頂層地址型別父類,其與子類的記憶體佈局相同
connect()
根據addr.sin_family
來判斷是哪一種地址型別並進行相應解析
IP 地址相關函式
#include <arpa/inet.h>
函式原型 | 功能描述 |
in_addr_t inet_addr(const char* strptr); | 將 IP 字串轉換為符合網路位元組序的整數 |
int inet_aton(const char *cp, struct_addr *inp); | 將 IP 字串轉換為符合網路位元組序的整數,成功返回 1, 失敗返回 0 |
char *inet_ntoa(struct in_addr in) | 將符合網路位元組序的整數地址轉換為字串形式 |
程式設計實驗:地址函式實驗
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <malloc.h>
int main()
{
unsigned int addr = inet_addr("1.2.3.4");
struct in_addr addr1 = {0x09080706};
struct in_addr addr2 = {0x05040302};
char *s1 = inet_ntoa(addr1);
char *s1_s = strcpy(malloc(32), s1);
char *s2 = inet_ntoa(addr2);
char *s2_s = strcpy(malloc(32), s2);
printf("addr = %x\n", addr);
printf("addr1 = %x\n", addr1.s_addr);
printf("addr2 = %x\n", addr2.s_addr);
printf("s1 = %s\n", s1);
printf("s2 = %s\n", s2); // 注意這裡 !!
printf("s1 == s2 : %d\n", s1 == s2); // 注意這裡 !!
printf("s1_s = %s\n", s1_s);
printf("s2_s = %s\n", s2_s);
printf("s1_s == s2_s : %d\n", s1_s == s2_s);
if (inet_aton("D.T.Software", &addr1)) { // 注意這裡 !!
printf("addr1 = %x\n", addr1.s_addr);
}
free(s1_s);
free(s2_s);
return 0;
}
輸出
addr = 4030201
addr1 = 9080706
addr2 = 5040302
s1 = 2.3.4.5
s2 = 2.3.4.5 // 注意,轉換結果被覆蓋 !!
s1 == s2 : 1 // 兩次為同一個地址 !!
s1_s = 6.7.8.9
s2_s = 2.3.4.5
s1_s == s2_s : 0
遺留的問題:如何增強服務端能力,同時支援多個客戶端?什麼是多播?什麼是廣播?