网络编程基础概念
1.網絡編程的基本概念
(1)IP地址
IP地址的作用是標識網絡中的一臺計算機,每一臺計算機都有一個IP地址。在程序中,通過IP地址來訪問一臺計算機。IP地址具有統一的格式,IP地址是32位長度的二進制數值,存儲空間是4個字節。
(2)端口
所謂端口,是計算機中為了標識計算機中訪問網絡的不同程序的編號。每一個程序訪問網絡時,都會分配一個標識符。程序在訪問網絡或接受網絡訪問時,會用這個標識符表示網絡數據屬于這個程序。端口號是一個無符號16位整數,對應的十進制取值范圍是0~65535。低于256的端口號是系統保留端口,主要用于標識系統進程。例如網站的www服務使用的端口號是80,FTP服務使用的端口號是21。端口號的作用是用于區分網絡通信中主機上不同的網絡應用程序。
(3)域名
用來代替IP地址以標識計算機的一種直觀名稱。例如百度的IP地址是202.108.22.43,百度的域名是www.baidu.com
(4)TCP與UDP
TCP和UDP是兩種不同的網絡傳輸方式。兩個不同計算機中的程序,使用IP地址和端口,使用一種約定的方法進行數據傳輸。TCP和UDP就是網絡中的兩種數據傳輸約定。主要的區別是進行數據傳輸時是否需要連接。
TCP是一種面向連接的傳輸方式。計算機A先呼叫計算機B,計算機接受連接后發出確認信息,計算機A收到確認信息后發送信息,計算機B接收信息后發送完畢信息。這時再關閉數據連接。這種方式是可靠的,缺點是傳輸過程復雜,需要占用較多的網絡資源。
UDP是一種無面向連接的傳輸方式。使用UDP傳送信息時,不建立連接,直接把信息發送到網絡上,由網絡完成信息的傳送。信息完成以后也不發送確認信息。這種方式是不可靠的,但是有良好的傳輸效率。在對傳輸可靠性要求不高時,可以選擇使用這種傳輸方式。(如果使用UDP協議進行數據通信,數據傳輸的可靠性由軟件開發人員編程實現)
2.套接字
(1)什么是套接字(socket=傳輸層協議+端口號+IP地址)
網絡中的兩個應用程序相互通信時,可以使用TCP或者UDP方式傳輸數據。對于開發者來說,更關心的是傳輸的數據,而不是TCP或者UDP協議本身。因此,制定了一種用于網絡傳輸數據的編程接口,成為套接字。區分不同應用程序進程間的網絡通信和連接,主要使用三個參數:通信的目的IP地址,使用的傳輸層協議,使用的端口號。
(2)套接字相關的數據結構
(3)套接字類型
套接字類型指的是在網絡通信中不同的數據傳輸方式。常用的套接字類型有以下三種:
流套接字:流套接字使用了面向連接的可靠的數據通信方式,即使用了TCP協議
數據報套接字:數據報套接字使用了面向無連接的數據傳輸方式,即使用了UDP協議
原始套接字:前面講述的兩種套接字是系統定義的,所有的信息都需要相應夫人方式進行封裝。原始套接字是沒有經過處理的IP數據包,可以根據自己程序的需要進行封裝。如果要訪問其他的協議,需要使用原始套接字來構造相應的協議。
3.域名與IP地址
在TCP/IP網絡中,通信雙方的主機必須知道彼此的IP地址方可進行通信,如果給出主機的域名,在開始正常的通信前必須把域名轉換成IP地址。這個域名到IP地址的轉換過程稱為域名解析
(1)用域名獲得主機的IP地址
在使用域名訪問網絡時,需要將這個域名轉換車成相應的IP地址。
用域名返回IP地址的函數是gethostbyname,函數的定義如下所示:
struct hostent* gethostbyname(const char name);
在參數列表中,name是一個表示域名的字符串。函數會把這個域名轉換成主機地址結構體返回。
結構體hostent的定義如下:
struct hostent
{
char *h_name;???? //正式的主機名稱
char **h_aliases;??? //主機的別名
int h_addrtype;?????? //主機名的類型
int h_length;??????? //地址的長度
char **h_addr_list;??? //從域名服務器取得的主機的地址
}
可能返回的錯誤信息如下所示:
HOST_NOT_FOUND:主機沒有找到
NO_ADDTRSS or NO_DATA:沒有ip地址或沒有數據
NO_RECOVERY:域名服務器發生錯誤
TRY_AGAIN:請稍后再試
(2)用IP地址返回域名
用一個IP地址可以查詢到這個IP地址的域名,需要使用的函數是gethostbyaddr,定義如下所示:
struct hostent* gethostbyaddr(const void *addr,socklen_t len,int type)
在參數列表中addr是一個保存了IP地址的字符串,len是這個IP地址的長度,type的值一般是AF_INET。函數的返回值是hostent類型的指針。如果轉換失敗,則返回NULL指針
4.網絡協議
所謂網絡協議,是指不同的計算機,不同的操作系統,在進行網絡通信時的統一約定。在編程中如何獲取協議信息
(1)由協議名取得協議數據
如TCP,UPD等,是協議的名稱。在編程時,需要用這些協議名稱取得這些協議的數據。函數getprotobyname的作用是按名稱取得一個協議的數據。getprotobyname函數定義如下:
struct protoent* getprotobyname(char *name);
name是一個表示協議名稱的字符串。返回值是一個protoent類型的結構體指針。結構體protoent的定義如下:
struct protoent
{
char *p_name; //協議的名稱
char **p_aliases;//協議的別名
int p_proto;//協議的序號
}
(2)用協議編號取得協議信息
知道了一個協議的編號,可以用getprotobynumber函數來取得這個協議的信息。這個函數的使用方法如下所示:
struct protoent* getprotobynumber(int proto);
在參數列表中,proto是一個協議的編號。函數會返回一個protoent類型的結構體指針
(3)取得系統支持的所有協議
函數getprotoent的作用是取得系統中支持的所有協議。getprotoent函數定義如下:
struct protoent* getprotoent(void);
這個函數沒有參數,每次調用時,依次返回一個系統支持的協議,返回一個struct protoent結構體指針,到達末尾時會返回NULL指針。系統中支持的協議類型,記錄在/etc/protocols文件中。
5.網絡服務
所謂網絡服務,是指網絡上的計算機通過運行程序,為其他計算機提供信息或運算的功能。例如打開一個網頁,是訪問了網站服務器上的服務,從服務器上下載下來了網頁文件。
(1)取得系統支持的網絡服務
函數getservent的作用是取得系統所支持的服務。getservent函數的定義如下所示:
struct servent* getservent(void);
這個函數沒有參數,返回一個servent類型的結構體指針。servent類型的定義如下所示:
struct servent
{
char *s_name; //服務名稱
char **s_aliases; //服務可能的別名
int s_port; //服務可能的端口號
char *s_proto; //服務使用的協議
}
每次調用這個函數時,會返回一個系統支持的服務。如果已經到達最后一個,則返回NULL。系統中支持的服務,放在/etc/services文件中。
(2)用名稱取得系統所支持的服務。
函數getservbyname可以用一個服務的名稱取得服務。getservbyname的定義如下:
struct servent* getservbyname(char *name,char *proto);
在參數列表中,name是服務的名稱,proto是該服務使用的協議。函數getservent可以查出參數所對應的系統服務,返回一個servent指針。如果沒有查詢到這個服務,會返回NULL指針
(3)用 端口號取得服務名稱
函數getservbyport可以從一個端口號取得服務的信息。函數getservbyport的定義如下所示:
struct servent* getservbyport(int port,char *proto);
在參數的列表中,port是一個端口的編號。需要注意的是,這個端口號需要用htons()進行轉換。proto是一個用來表示協議的字符串。這個函數會返回這個端口服務的servent類型的指針。
6.網絡地址的交換
網絡IP地址本是用32位二進制數表示的,為了記憶方便,可以用點分十進制數來表示IP地址。網絡傳輸和計算機內部的字符存儲的方式是不同的,需要用相關函數將端口號進行轉換。、
(1)將網絡地址轉換成整型
函數inet_addr可以將一個網絡IP地址轉換成一個十進制長整型數。inet_addr函數的定義如下:
long inet_addr(char *cp);
函數的參數cp是一個表示IP地址的字符串。函數會將這個IP地址轉換成一個長整型數。使用這個函數之前,需要在程序中包含頭文件:sys/socket.h netinet/in.h arpa/inet.h
(2)將長整型地址轉換成網絡地址
函數inet_ntoa可以將整型數地址轉換成點分十進制數網絡地址。函數inet_ntoa定義如下:
char * inet_ntoa(struct in_addr in);
函數的參數in是一個in_addr類型的結構體,這個結構體的定義如下:
struct in_addr
{
uint32_t s_addr;
}
結構體中只有一個成員,s_addr是一個長整型數,用來存儲一個長整型數的IP地址。函數inet_ntoa會把這個長整型數轉換成一個字符串返回。使用這個函數之前,需要包含以下頭文件:sys/socket.h netinet/in.h arap/inet.h
(3) 主機字符順序與網絡字符順序的轉換
計算機中的字符與網絡中的字符存儲順序是不同的。計算機中的整型數與網絡中的整型數進行交換時,需要用相關的函數進行轉換。如果計算機中的長整型地址轉換成網絡字符順序的整型地址,使用htonl函數。這些函數如下所示:
uint32_t htonl(uint32_t hostlong);
uint16_t htonl(uint16_t hostlong);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohl(uint16_t netlong);
以上的參數都是需要轉換的整型數,函數把這些整型數轉換以后返回。使用這些函數以前,需要在程序前包含arpa/inet.h
7.錯誤處理
(1)herror函數顯示錯誤
函數herror可以顯示上一個網絡函數發生的錯誤。函數herror的定義如下:
void herror(const char *s);
這個函數的參數是一個字符串,調用這個函數時,會先輸出這個字符串,然后直接輸出錯誤信息。輸出的錯誤信息是上一個網絡相關的函數發生的錯誤。使用這個函數時,需要在程序最前面包含netdb.h文件
(2)捕獲錯誤編號
在網絡程序中,可以使用 extern int h_errno;捕獲發生錯誤的編號。用hstrerror函數來輸出這個錯誤信息。這個函數的定義如下;
char* hstrerror(int err);
這個函數的編號是已經捕獲的錯誤信息的編號,函數會返回這個編號所對應的錯誤信息。在使用這個函數時,需要在程序最前面包含netdb.h文件???????????????????????
總結
- 上一篇: DruidDataSource详解部分(
- 下一篇: 2019高速数据采集卡动态