1882. 網絡相關概念
(1)套接口的概念:
套接口網絡編程實現文件傳輸,也叫“套接字”。是操作系統內核中的一個數據結構,它是網絡中的節點進行相互通信的門戶。它是網絡進程的ID。網絡通信,歸根到底還是進程間的通信(不同計算機上的進程間通信)。在網絡中,每一個節點(計算機或路由)都有一個網絡地址,也就是IP地址。兩個進程通信時,首先要確定各自所在的網絡節點的網絡地址。但是,網絡地址只能確定進程所在的計算機,而一臺計算機上很可能同時運行著多個進程,所以僅憑網絡地址還不能確定到底是和網絡中的哪一個進程進行通信,因此套接口中還需要包括其他的信息,也就是端口號(PORT)。在一臺計算機中,一個端口號一次只能分配給一個進程,也就是說,在一臺計算機中,端口號和進程之間是一一對應關系。所以,使用端口號和網絡地址的組合可以唯一的確定整個網絡中的一個網絡進程。
例如,如網絡中某一臺計算機的IP為10.92.20.160,操作系統分配給計算機中某一應用程序進程的端口號為1500,則此時 10.92.20.160 1500就構成了一個套接口。
(2)端口號的概念:
在網絡技術中,端口大致有兩種意思:一是物理意義上的端口,如集線器、交換機、路由器等用于連接其他網絡設備的接口。二是指TCP/IP協議中的端口,端口號的范圍從0~65535,一類是由互聯網指派名字和號碼公司ICANN負責分配給一些常用的應用程序固定使用的“周知的端口”,其值一般為0~1023.例如http的端口號是80,ftp為21,ssh為22,為23等。還有一類是用戶自己定義的,通常是大于1024的整型值。
(3)ip地址的表示:
通常用戶在表達IP地址時采用的是點分十進制表示的數值(或者是為冒號分開的十進制Ipv6地址),而在通常使用的編程中使用的則是二進制值,這就需要將這兩個數值進行轉換。
ipv4地址:32bit, 4字節,通常采用點分十進制記法。
例如對于:11
點分十進制表示為:128.11.3.31
2.1. 概念
Linux中的網絡編程是通過接口來進行的。是一種特殊的I/O接口,它也是一種文件描述符。它是一種常用的進程之間通信機制,通過它不僅能實現本地機器上的進程之間的通信,而且通過網絡能夠在不同機器上的進程之間進行通信。
每一個都用一個半相關描述{協議、本地地址、本地端口}來表示;一個完整的套接字則用一個相關描述{協議、本地地址、本地端口、遠程地址、遠程端口}來表示。也有一個類似于打開文件的函數調用,該函數返回一個整型的描述符,隨后的連接建立、數據傳輸等操作都是通過來實現的;
2.2. 類型
(1)流式() à用于TCP通信
流式套接字提供可靠的、面向連接的通信流;它使用TCP協議,從而保證了數據傳輸的正確性和順序性。
(2)數據報() à用于UDP通信
數據報套接字定義了一種無連接的服務,數據通過相互獨立的報文進行傳輸,是無序的,并且不保證是可靠、無差錯的。它使用數據報協議UDP。
(3)原始 () à用于新的網絡協議實現的測試等
原始套接字允許對底層協議如IP或ICMP進行直接訪問,它功能強大但使用較為不便,主要用于一些協議的開發。
2.3. 信息數據結構
1struct?sockaddr
2{
3????unsigned?short?sa_family;?/地址族/
4????char?sa_data[14];?/14字節的協議地址,包含該socket的IP地址和端口號。/
5};
6struct?sockaddr_in
7{
8????short?int?sa_family;?/地址族/
9????unsigned?short?int?sin_port;?/端口號/
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地址,網絡字節序?/
16};
17頭文件
18sa_family:AF_INET??aIPv4協議???AF_INET6??àIPv6協議
2.4. 數據存儲優先順序的轉換
計算機數據存儲有兩種字節優先順序:高位字節優先(稱為大端模式)和低位字節優先(稱為小端模式)。內存的低地址存儲數據的低字節,高地址存儲數據的高字節的方式叫小端模式。內存的高地址存儲數據的低字節,低地址存儲數據高字節的方式稱為大端模式。
eg:對于內存中存放的數來說
如果是采用大端模式存放的,則其真實的數是:
如果是采用小端模式存放的,則其真實的數是:
如果稱某個系統所采用的字節序為主機字節序,則它可能是小端模式的,也可能是大端模式的。而端口號和IP地址都是以網絡字節序存儲的,不是主機字節序,網絡字節序都是大端模式。要把主機字節序和網絡字節序相互對應起來,需要對這兩個字節存儲優先順序進行相互轉化。這里用到四個函數:htons(),ntohs(),htonl()和ntohl().這四個地址分別實現網絡字節序和主機字節序的轉化,這里的h代表host,n代表,s代表short,l代表long。通常16位的IP端口號用s代表,而IP地址用l來代表。
函數原型如下:
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. 地址格式轉化
通常用戶在表達地址時采用的是點分十進制表示的數值(或者是為冒號分開的十進制Ipv6地址)網絡編程實現文件傳輸,而在通常使用的編程中使用的則是32位的網絡字節序的二進制值,這就需要將這兩個數值進行轉換。這里在Ipv4中用到的函數有()、()和(),而IPV4和Ipv6兼容的函數有()和()。
IPv4的函數原型:
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);
函數():將點分十進制數的IP地址轉換成為網絡字節序的32位二進制數值。返回值:成功,則返回1,不成功返回0.
參數:存放輸入的點分十進制數IP地址字符串。
參數:傳出參數,保存網絡字節序的32位二進制數值。
函數():將網絡字節序的32位二進制數值轉換為點分十進制的IP地址。
函數():功能與相同,但是結果傳遞的方式不同。()若成功則返回32位二進制的網絡字節序地址。
IPv4和IPv6的函數原型:
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);
函數跟實現的功能類似,只是多了參數,該參數指定為,表示是IPv4協議,如果是,表示IPv6協議。
函數跟類似,其中len表示表示轉換之后的長度(字符串的長度)。
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. 名字地址轉化
通常,人們在使用過程中都不愿意記憶冗長的IP地址,尤其到Ipv6時,地址長度多達128位,那時就更加不可能一次性記憶那么長的IP地址了。因此,使用主機名或域名將會是很好的選擇。主機名與域名的區別:主機名通常在局域網里面使用,通過/etc/hosts文件,主機名可以解析到對應的ip;域名通常是再上使用。
眾所周知,百度的域名為:,而這個域名其實對應了一個百度公司的IP地址,那么百度公司的IP地址是多少呢?我們可以利用ping 來得到百度公司的ip地址,如圖。那么,系統是如何將 這個域名轉化為IP地址220.181.111.148的呢?
在linux中,有一些函數可以實現主機名和地址的轉化,最常見的有()、()等,它們都可以實現IPv4和IPv6的地址和主機名之間的轉化。其中()是將主機名轉化為IP地址,()則是逆操作,是將IP地址轉化為主機名。
函數原型:
1#include?
2struct?hostent*?gethostbyname(const?char*?hostname);
3struct?hostent*?gethostbyaddr(const?char*?addr,?size_t?len,?int?family);