1882. 網(wǎng)絡(luò)相關(guān)概念
(1)套接口的概念:
套接口網(wǎng)絡(luò)編程實(shí)現(xiàn)文件傳輸,也叫“套接字”。是操作系統(tǒng)內(nèi)核中的一個(gè)數(shù)據(jù)結(jié)構(gòu),它是網(wǎng)絡(luò)中的節(jié)點(diǎn)進(jìn)行相互通信的門戶。它是網(wǎng)絡(luò)進(jìn)程的ID。網(wǎng)絡(luò)通信,歸根到底還是進(jìn)程間的通信(不同計(jì)算機(jī)上的進(jìn)程間通信)。在網(wǎng)絡(luò)中,每一個(gè)節(jié)點(diǎn)(計(jì)算機(jī)或路由)都有一個(gè)網(wǎng)絡(luò)地址,也就是IP地址。兩個(gè)進(jìn)程通信時(shí),首先要確定各自所在的網(wǎng)絡(luò)節(jié)點(diǎn)的網(wǎng)絡(luò)地址。但是,網(wǎng)絡(luò)地址只能確定進(jìn)程所在的計(jì)算機(jī),而一臺(tái)計(jì)算機(jī)上很可能同時(shí)運(yùn)行著多個(gè)進(jìn)程,所以僅憑網(wǎng)絡(luò)地址還不能確定到底是和網(wǎng)絡(luò)中的哪一個(gè)進(jìn)程進(jìn)行通信,因此套接口中還需要包括其他的信息,也就是端口號(hào)(PORT)。在一臺(tái)計(jì)算機(jī)中,一個(gè)端口號(hào)一次只能分配給一個(gè)進(jìn)程,也就是說,在一臺(tái)計(jì)算機(jī)中,端口號(hào)和進(jìn)程之間是一一對(duì)應(yīng)關(guān)系。所以,使用端口號(hào)和網(wǎng)絡(luò)地址的組合可以唯一的確定整個(gè)網(wǎng)絡(luò)中的一個(gè)網(wǎng)絡(luò)進(jìn)程。
例如,如網(wǎng)絡(luò)中某一臺(tái)計(jì)算機(jī)的IP為10.92.20.160,操作系統(tǒng)分配給計(jì)算機(jī)中某一應(yīng)用程序進(jìn)程的端口號(hào)為1500,則此時(shí) 10.92.20.160 1500就構(gòu)成了一個(gè)套接口。
(2)端口號(hào)的概念:
在網(wǎng)絡(luò)技術(shù)中,端口大致有兩種意思:一是物理意義上的端口,如集線器、交換機(jī)、路由器等用于連接其他網(wǎng)絡(luò)設(shè)備的接口。二是指TCP/IP協(xié)議中的端口,端口號(hào)的范圍從0~65535,一類是由互聯(lián)網(wǎng)指派名字和號(hào)碼公司ICANN負(fù)責(zé)分配給一些常用的應(yīng)用程序固定使用的“周知的端口”,其值一般為0~1023.例如http的端口號(hào)是80,ftp為21,ssh為22,為23等。還有一類是用戶自己定義的,通常是大于1024的整型值。
(3)ip地址的表示:
通常用戶在表達(dá)IP地址時(shí)采用的是點(diǎn)分十進(jìn)制表示的數(shù)值(或者是為冒號(hào)分開的十進(jìn)制Ipv6地址),而在通常使用的編程中使用的則是二進(jìn)制值,這就需要將這兩個(gè)數(shù)值進(jìn)行轉(zhuǎn)換。
ipv4地址:32bit, 4字節(jié),通常采用點(diǎn)分十進(jìn)制記法。
例如對(duì)于:11
點(diǎn)分十進(jìn)制表示為:128.11.3.31
2.1. 概念
Linux中的網(wǎng)絡(luò)編程是通過接口來進(jìn)行的。是一種特殊的I/O接口,它也是一種文件描述符。它是一種常用的進(jìn)程之間通信機(jī)制,通過它不僅能實(shí)現(xiàn)本地機(jī)器上的進(jìn)程之間的通信,而且通過網(wǎng)絡(luò)能夠在不同機(jī)器上的進(jìn)程之間進(jìn)行通信。
每一個(gè)都用一個(gè)半相關(guān)描述{協(xié)議、本地地址、本地端口}來表示;一個(gè)完整的套接字則用一個(gè)相關(guān)描述{協(xié)議、本地地址、本地端口、遠(yuǎn)程地址、遠(yuǎn)程端口}來表示。也有一個(gè)類似于打開文件的函數(shù)調(diào)用,該函數(shù)返回一個(gè)整型的描述符,隨后的連接建立、數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^來實(shí)現(xiàn)的;
2.2. 類型
(1)流式() à用于TCP通信
流式套接字提供可靠的、面向連接的通信流;它使用TCP協(xié)議,從而保證了數(shù)據(jù)傳輸?shù)恼_性和順序性。
(2)數(shù)據(jù)報(bào)() à用于UDP通信
數(shù)據(jù)報(bào)套接字定義了一種無連接的服務(wù),數(shù)據(jù)通過相互獨(dú)立的報(bào)文進(jìn)行傳輸,是無序的,并且不保證是可靠、無差錯(cuò)的。它使用數(shù)據(jù)報(bào)協(xié)議UDP。
(3)原始 () à用于新的網(wǎng)絡(luò)協(xié)議實(shí)現(xiàn)的測試等
原始套接字允許對(duì)底層協(xié)議如IP或ICMP進(jìn)行直接訪問,它功能強(qiáng)大但使用較為不便,主要用于一些協(xié)議的開發(fā)。
2.3. 信息數(shù)據(jù)結(jié)構(gòu)
1struct?sockaddr
2{
3????unsigned?short?sa_family;?/地址族/
4????char?sa_data[14];?/14字節(jié)的協(xié)議地址,包含該socket的IP地址和端口號(hào)。/
5};
6struct?sockaddr_in
7{
8????short?int?sa_family;?/地址族/
9????unsigned?short?int?sin_port;?/端口號(hào)/
10????struct?in_addr?sin_addr;?/IP地址/
11????unsigned?char?sin_zero[8];?/填充0?以保持與struct?sockaddr同樣大小/
12};
13struct?in_addr
14{
15unsigned?long?int??s_addr;?/?32位IPv4地址,網(wǎng)絡(luò)字節(jié)序?/
16};
17頭文件
18sa_family:AF_INET??aIPv4協(xié)議???AF_INET6??àIPv6協(xié)議
2.4. 數(shù)據(jù)存儲(chǔ)優(yōu)先順序的轉(zhuǎn)換
計(jì)算機(jī)數(shù)據(jù)存儲(chǔ)有兩種字節(jié)優(yōu)先順序:高位字節(jié)優(yōu)先(稱為大端模式)和低位字節(jié)優(yōu)先(稱為小端模式)。內(nèi)存的低地址存儲(chǔ)數(shù)據(jù)的低字節(jié),高地址存儲(chǔ)數(shù)據(jù)的高字節(jié)的方式叫小端模式。內(nèi)存的高地址存儲(chǔ)數(shù)據(jù)的低字節(jié),低地址存儲(chǔ)數(shù)據(jù)高字節(jié)的方式稱為大端模式。
eg:對(duì)于內(nèi)存中存放的數(shù)來說
如果是采用大端模式存放的,則其真實(shí)的數(shù)是:
如果是采用小端模式存放的,則其真實(shí)的數(shù)是:
如果稱某個(gè)系統(tǒng)所采用的字節(jié)序?yàn)橹鳈C(jī)字節(jié)序,則它可能是小端模式的,也可能是大端模式的。而端口號(hào)和IP地址都是以網(wǎng)絡(luò)字節(jié)序存儲(chǔ)的,不是主機(jī)字節(jié)序,網(wǎng)絡(luò)字節(jié)序都是大端模式。要把主機(jī)字節(jié)序和網(wǎng)絡(luò)字節(jié)序相互對(duì)應(yīng)起來,需要對(duì)這兩個(gè)字節(jié)存儲(chǔ)優(yōu)先順序進(jìn)行相互轉(zhuǎn)化。這里用到四個(gè)函數(shù):htons(),ntohs(),htonl()和ntohl().這四個(gè)地址分別實(shí)現(xiàn)網(wǎng)絡(luò)字節(jié)序和主機(jī)字節(jié)序的轉(zhuǎn)化,這里的h代表host,n代表,s代表short,l代表long。通常16位的IP端口號(hào)用s代表,而IP地址用l來代表。
函數(shù)原型如下:
1#include?
2
3#include?
4
5#include?
6
7int?inet_aton(const?char?*straddr,?struct?in_addr?*addrptr);
8
9char?*inet_ntoa(struct?in_addr?inaddr);
10
11in_addr_t?inet_addr(const?char?*straddr);
2.5. 地址格式轉(zhuǎn)化
通常用戶在表達(dá)地址時(shí)采用的是點(diǎn)分十進(jìn)制表示的數(shù)值(或者是為冒號(hào)分開的十進(jìn)制Ipv6地址)網(wǎng)絡(luò)編程實(shí)現(xiàn)文件傳輸,而在通常使用的編程中使用的則是32位的網(wǎng)絡(luò)字節(jié)序的二進(jìn)制值,這就需要將這兩個(gè)數(shù)值進(jìn)行轉(zhuǎn)換。這里在Ipv4中用到的函數(shù)有()、()和(),而IPV4和Ipv6兼容的函數(shù)有()和()。
IPv4的函數(shù)原型:
1#include?
2
3#include?
4
5#include?
6
7int?inet_aton(const?char?*straddr,?struct?in_addr?*addrptr);
8
9char?*inet_ntoa(struct?in_addr?inaddr);
10
11in_addr_t?inet_addr(const?char?*straddr);
函數(shù)():將點(diǎn)分十進(jìn)制數(shù)的IP地址轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序的32位二進(jìn)制數(shù)值。返回值:成功,則返回1,不成功返回0.
參數(shù):存放輸入的點(diǎn)分十進(jìn)制數(shù)IP地址字符串。
參數(shù):傳出參數(shù),保存網(wǎng)絡(luò)字節(jié)序的32位二進(jìn)制數(shù)值。
函數(shù)():將網(wǎng)絡(luò)字節(jié)序的32位二進(jìn)制數(shù)值轉(zhuǎn)換為點(diǎn)分十進(jìn)制的IP地址。
函數(shù)():功能與相同,但是結(jié)果傳遞的方式不同。()若成功則返回32位二進(jìn)制的網(wǎng)絡(luò)字節(jié)序地址。
IPv4和IPv6的函數(shù)原型:
1#include?
2
3int?inet_pton(int?family,?const?char?*src,?void?*dst);
4
5const?char?*inet_ntop(int?family,?const?void?*src,?char?*dst,?socklen_t?len);
函數(shù)跟實(shí)現(xiàn)的功能類似,只是多了參數(shù),該參數(shù)指定為,表示是IPv4協(xié)議,如果是,表示IPv6協(xié)議。
函數(shù)跟類似,其中l(wèi)en表示表示轉(zhuǎn)換之后的長度(字符串的長度)。
1Example:
2#include?
3#include?
4#include?
5#include?
6int?main()
7{
8????char?ip[]?=?"192.168.0.101";
9????struct?in_addr?myaddr;
10????/*?inet_aton?*/
11????int?iRet?=?inet_aton(ip,?&myaddr);
12????printf("%x\n",?myaddr.s_addr);
13
14???/*?inet_addr?*/
15???printf("%x\n",?inet_addr(ip));
16
17???/*?inet_pton?*/
18???iRet?=?inet_pton(AF_INET,?ip,?&myaddr);
19???printf("%x\n",?myaddr.s_addr);
20
21???myaddr.s_addr?=?0xac100ac4;
22???/*?inet_ntoa?*/
23???printf("%s\n",?inet_ntoa(myaddr));
24
25???/*?inet_ntop?*/
26???inet_ntop(AF_INET,?&myaddr,?ip,?16);
27???puts(ip);
28????return?0;
29}
2.6. 名字地址轉(zhuǎn)化
通常,人們?cè)谑褂眠^程中都不愿意記憶冗長的IP地址,尤其到Ipv6時(shí),地址長度多達(dá)128位,那時(shí)就更加不可能一次性記憶那么長的IP地址了。因此,使用主機(jī)名或域名將會(huì)是很好的選擇。主機(jī)名與域名的區(qū)別:主機(jī)名通常在局域網(wǎng)里面使用,通過/etc/hosts文件,主機(jī)名可以解析到對(duì)應(yīng)的ip;域名通常是再上使用。
眾所周知,百度的域名為:,而這個(gè)域名其實(shí)對(duì)應(yīng)了一個(gè)百度公司的IP地址,那么百度公司的IP地址是多少呢?我們可以利用ping 來得到百度公司的ip地址,如圖。那么,系統(tǒng)是如何將 這個(gè)域名轉(zhuǎn)化為IP地址220.181.111.148的呢?
在linux中,有一些函數(shù)可以實(shí)現(xiàn)主機(jī)名和地址的轉(zhuǎn)化,最常見的有()、()等,它們都可以實(shí)現(xiàn)IPv4和IPv6的地址和主機(jī)名之間的轉(zhuǎn)化。其中()是將主機(jī)名轉(zhuǎn)化為IP地址,()則是逆操作,是將IP地址轉(zhuǎn)化為主機(jī)名。
函數(shù)原型:
1#include?
2struct?hostent*?gethostbyname(const?char*?hostname);
3struct?hostent*?gethostbyaddr(const?char*?addr,?size_t?len,?int?family);