Linux網路程式設計二

2021-08-13 04:40:43 字數 3487 閱讀 7821

一、大端、小端和網路位元組序

小端位元組序:little-endian,將低位元組存放在記憶體的起始位址;

大端位元組序:big-endian,將高位元組存放在記憶體的其實位址。

例如,數字index=0x11223344,在大小端位元組序方式下其儲存形式為:

上圖一目了然的可以看出大小端位元組序的區別。

還有另外乙個概念就是網路位元組序。網路位元組順序是tcp/ip中規定好的一種資料表示格式,它與具體的cpu型別、作業系統等無關,從而可以保證資料在不同主機之間傳輸時能夠被正確解釋。網路位元組順序採用big endian方式。注意:x86系列cpu都是小端little-endian位元組序,即低位元組存低位,高位元組存高位。

為此,linux專門提供了位元組轉換函式.

unsigned long  int htonl(unsigned long  int hostlong)

unsigned short int htons(unisgned short int hostshort)

unsigned long  int ntohl(unsigned long  int netlong)

unsigned short int ntohs(unsigned short int netshort)

在這四個轉換函式中,h代表host,n代表 network,s代表short,l代表long

。htonl()函式的意義是將本機器上的long資料轉化為網路上的long。其他幾個函式的意義也差不多。

看個例子:

也就是說對於從網路上接收到的非單子節的基本資料型別資料,首先需要用ntohl(s)將其轉換成本地位元組序;同理,發往網路的非單子節的基本資料型別資料,首先用htonl(s)將其轉換成網路位元組序。這裡最常見的就是ip位址和埠號。

二、點分十進位制格式的ip位址和32bit的ip位址

我們常見的ip位址都是以點分十進位制格式表示,例如「172.18.1.231」。而在程式中基本是以如下的結構表示乙個ip:

struct in_addr ;

它和點分十進位制格式的ip位址可以通過一組api實現相互轉換:

int inet_aton(const char *cp,struct in_addr *inp) 無效的位址cp則返回0;否則返回非0

char *inet_ntoa(struct in_addr in) 將乙個32位的ip位址轉換成點分十進位制字串。

這兩個函式所要求的struct in_addr{}引數均為網路位元組序。

繼續看例子:

「192.168.11.23」轉換成數字就是0xc0a80b17,是網路位元組序的。如果直接列印,那麼本地按照小端位元組序來輸出,結果為net addr = 170ba8c0,剛好和實際相反。當我們先將其轉換成本地位元組序,然後再輸出時結果就ok了,即host addr = c0a80b17。同理,inet_ntoa()也類似。

三、網路主機名和ip位址的對應關係

在做網路程式設計時經常要碰到的乙個問題就是根據對方主機名來獲取其ip位址,或者根據ip位址反過來解析主機名和其他資訊。linux提供了兩個常用的api:

struct hostent *gethostbyname(const char *name);

struct hostent *gethostbyaddr(const void *addr, int len, int type);

這兩個函式失敗時返回null且設定h_errno錯誤變數,呼叫hstrerror(h_errno)或者herror("error");可以得到詳細的出錯資訊。成功時均返回如下結構:        

struct hostent

#define h_addr  h_addr_list[0]  /*後向相容 */

gethostbyname可以將機器名(如www.google.com)轉換為乙個結構指標,gethostbyaddr可以將乙個32位的ip位址(c0a80001)轉換為結構指標。對於gethostbyaddr函式來說,輸入引數「addr」的型別根據引數「type」來確定,目前type僅取af_inet或af_inet6。例如,type=2(即af_inet),則addr就必須為struct in_addr{}型別。

繼續看例子:       

#include

#include

#include

#include

#include

#include

#include

int main(int arg,char** argv)

printf("name = %s\n",host->h_name);

printf("aliases = %s\n",*host->h_aliases);

printf("add type = %d\n",host->h_addrtype);

printf("len = %d\n",host->h_length);

printf("ip=%s\n",inet_ntoa(*(struct in_addr*)host->h_addr));

printf("******************************===\n");

struct in_addr maddr;

if(0 == inet_aton(argv[2],&maddr))

char* c = (char*)&maddr;

printf("org = %x.%x.%x.%x\n",*(c)&0xff,*(c+1)&0xff,*(c+2)&0xff,*(c+3)&0xff);

if(null == (host2 = gethostbyaddr(&maddr,4,2)))

printf("name = %s\n",host2->h_name);

printf("aliases = %s\n",*host2->h_aliases);

printf("add type = %d\n",host2->h_addrtype);

printf("len = %d\n",host2->h_length);

printf("ip=%s\n",inet_ntoa(*(struct in_addr*)host2->h_addr));

return 0; }

執行結果如下:

當我們呼叫gethostbyaddr根據cu主頁的ip位址獲取其站點資訊時返回的錯誤是「未知的主機」錯誤,原因留給大家自己思考吧。這充分說明對了於gethostbyname()函式和gethostbyaddr()函式的呼叫一定要判斷其返回值。

Linux 網路程式設計(二)UDP程式設計

資料報通訊 對於資料報通訊的伺服器端來說,它不必再在乙個埠上偵聽,以等待建立連線,而只需生成乙個埠描述符,並且把這個埠描述符繫結到本地位址上就可以了。udp網路程式設計具體的操作流程為 使用系統呼叫socket 來獲得檔案描述符,該呼叫的宣告格式為 connect 系統呼叫由客戶端呼叫,它的用法如下...

Linux網路程式設計基礎 二

1 位元組轉換函式 在網路上面有著許多態別的機器,這些機器在表示資料的位元組順序是不同的,比如i386晶元是低位元組在記憶體位址的低端,高位元組在高階,而alpha晶元卻相反.為了統一起來,在linux下面,有專門的位元組轉換函式.unsigned long int htonl unsigned l...

Linux網路程式設計基礎二

服務套和客戶機的資訊函式 1 位元組轉換函式 在網路上面有著許多態別的機器,這些機器在表示資料的位元組順序是不同的,比如i386晶元是低位元組在記憶體位址的低端,高位元組在高階,而alpha晶元卻相反.為了統一起來,在linux 下面,有專門的位元組轉換函式.unsigned long int ht...