1. 程式人生 > >ntohs, ntohl, htons,htonl的比較和詳解

ntohs, ntohl, htons,htonl的比較和詳解

假設在x86平臺上,有一個int型變數,在記憶體中的內部由低到高分別是:0x12,0x34,0x56,0x78當通過網路傳送該資料時,正確的傳送順序是

0x78,0x56,0x34,0x12

  • X86 系列 CPU都是 little-endian 的,所以int 型變數值為 0x78563412, 網路傳送資料時,採用大段,先發送高位再發送低位  

ntohs =net to host short int 16位
htons=host to net short int 16位
ntohl =net to host long int 32位
htonl=host to net long int 32位

網路位元組順序NBO(Network Byte Order)

按從高到低的順序儲存,在網路上使用同一的網路位元組順序,可避免相容性問題;

主機位元組順序HBO(Host Byte Order)

不同的機器HBO不相同,與CPU的設計有關,資料的順序是由CPU決定的,而與作業系統無關;

如Intel x86結構下,short型數0x1234表示為34 12,int型數0x12345678表示為78 56 34 12;

如IBM power PC結構下,short型數0x1234表示為 12 34,int型數0x12345678表示為 12 34 56 78.

由於這個原因,不同體系結構的機器之間不能直接通訊,所以要轉換成一種約定的順序,也就是網路位元組順序,其實就是如同power pc那樣的順序。在PC開發中有ntohl和htonl函式可以用來進行網路位元組和主機位元組的轉換

linx系統下,htonl() htons() ntohl() ntohs()的標頭檔案及函式定義如下:

#include <arpa/inet.h>

uint32_t htonl(uint32_t hostlong);

uint16_t htons(uint16_t hostshort);

uint32_t ntohl(uint32_t netlong);

uint16_t ntohs(uint16_t netshort);

在windows下,htonl() htons() ntohl() ntohs()的使用說明:

ntohs()

簡述:

將一個無符號短整形數從網路位元組順序轉換為主機位元組順序。

#include <winsock.h>
u_short PASCAL FAR ntohs( u_short netshort);
netshort:一個以網路位元組順序表達的16位數。
註釋:本函式將一個16位數由網路位元組順序轉換為主機位元組順序。
返回值:ntohs()返回一個以主機位元組順序表達的數。

htons()

 簡述:將主機的無符號短整形數轉換成網路位元組順序。
 #include <winsock.h>
 u_short PASCAL FAR htons( u_short hostshort);
 hostshort:主機位元組順序表達的16位數。
 註釋:本函式將一個16位數從主機位元組順序轉換成網路位元組順序。
 返回值:htons()返回一個網路位元組順序的值。
  

  這2個函式提供了主機位元組順序與網路位元組順序的轉換
  比如網路位元組 為 00 01
  u_short    a;如何直接對應的話    a=0100; 為什麼呢?因為主機是從高位元組到低位元組的,所以應該轉化後a=ntohs(0001); 這樣 a=0001;

  htonl()表示將32位的主機位元組順序轉化為32位的網路位元組順序 htons()表示將16位的主機位元組順序轉化為16位的網路位元組順序(ip地址是32位的埠號是16位的 )

  將IP地址轉換成長整型:首先,假設你已經有了一個sockaddr_in結構體ina,你有一個IP地址"132.241.5.10" 要儲存在其中,你就要用到函式inet_addr(),將IP地址從點數格式轉換成無符號長整型。使用方法如下:ina.sin_addr.s_addr = inet_addr("132.241.5.10");
  注意,inet_addr()返回的地址已經是網路位元組格式,所以你無需再呼叫函式htonl()。
  我們現在發現上面的程式碼片斷不是十分完整的,因為它沒有錯誤檢查。顯而易見,當inet_addr()發生錯誤時返回-1。記住這些二進位制數字?(無符號數)-1僅僅和IP地址255.255.255.255相符合!但這可是廣播地址!所以,記住要先進行錯誤檢查。
  

  怎樣將一個in_addr結構體輸出成點數格式?你要用到函式 inet_ntoa()("ntoa"的含義是"network to ascii"),就像這樣:printf("%s",inet_ntoa(ina.sin_addr));它將輸出IP地址。需要注意的是inet_ntoa()將結構體in_addr作為一個引數,不是長整形。同樣需要注意的是它返回的是一個指向一個字元的指標。它是一個由inet_ntoa()控制的靜態的固定的指標,所以每次呼叫 inet_ntoa(),它就將覆蓋上次呼叫時所得的IP地址。例如:
char *a1, *a2;
.

htons和htonl都是把主機位元組序轉換成網路位元組序。那什麼時候用htons,什麼時候用htonl??聽網上說一個是16位一個是32位,但是如何去判斷?假設servaddr.sin_port = htons(5555);用htonl可以嗎?根據什麼可以判斷?

根據要轉換的值是否超過16位來決定,5555轉換為2進製為1 0101 1011 0011 ,為13位,所以一般用htons,當然用htonl也可以;
但是如果要轉換的數 轉換成2進位制超過16位,則只能用htonl,此時如果用htons,16位以上的數捨去,造成資料值偏差。


.
a1 = inet_ntoa(ina1.sin_addr);
a2 = inet_ntoa(ina2.sin_addr);
printf("address 1: %s ",a1);
printf("address 2: %s ",a2);
輸出如下:
address 1: 132.241.5.10
address 2: 132.241.5.10
假如你需要儲存這個IP地址,使用strcopy()函式來指向你自己的字元指標。

  inet_ntoa()
簡述:
 將網路地址轉換成“.”點隔的字串格式。
  #include <winsock.h>
  char FAR* PASCAL FAR inet_ntoa( struct in_addr in);
  in:一個表示Internet主機地址的結構。
 註釋:
    本函式將一個用in引數所表示的Internet地址結構轉換成以“.” 間隔的諸如“a.b.c.d”的字串形式。請注意inet_ntoa()返回的字串存放在WINDOWS套介面實現所分配的記憶體中。應用程式不應假設該記憶體是如何分配的。在同一個執行緒的下一個WINDOWS套介面呼叫前,資料將保證是有效。
 返回值:
    若無錯誤發生,inet_ntoa()返回一個字元指標。否則的話,返回NVLL。其中的資料應在下一個WINDOWS套介面呼叫前複製出來。
參見:   inet_addr().


測試程式碼如下
#pragma   comment   (lib,"Ws2_32.lib")

//noths.obj : error LNK2001: unresolved external ymbol [email protected]
#include <winsock.h>
#include <iostream.h>
#include <stdio.h>
int main(int aargc, char* argv[])
{
         struct in_addr addr1,addr2;
         unsigned long l1,l2;
         l1= inet_addr("192.168.0.74");
         l2 = inet_addr("211.100.21.179");
         memcpy(&addr1, &l1, 4);
         memcpy(&addr2, &l2, 4);

         printf("%s : %s \n", inet_ntoa(addr1), inet_ntoa(addr2));    //注意這一句的執行結果

         printf("%s \n", inet_ntoa(addr1));
         printf("%s \n", inet_ntoa(addr2));
         return 0;
}
實際執行結果如下:
192.168.0.74 : 192.168.0.74       //從這裡可以看出,printf裡的inet_ntoa只運行了一次。
192.168.0.74
211.100.21.179
  inet_ntoa返回一個char *,而這個char *的空間是在inet_ntoa裡面靜態分配的,所以inet_ntoa後面的呼叫會覆蓋上一次的呼叫。第一句printf的結果只能說明在printf裡面的可變引數的求值是從右到左的,僅此而已。


 inet_ntoa  將一個十進位制網路位元組序轉換為點分十進位制IP格式的字串。
inet_addr  將一個點分十進位制的IP轉換成一個長整數型數

相關推薦

ntohs, ntohl, htons,htonl比較

假設在x86平臺上,有一個int型變數,在記憶體中的內部由低到高分別是:0x12,0x34,0x56,0x78當通過網路傳送該資料時,正確的傳送順序是 0x78,0x56,0x34,0x12 X86 系列 CPU都是 little-endian 的,所以int 型變

htonl()函數

理解 問題 自定義 大端 編譯器 正常 lin 代碼 ret 在《Linux網絡編程》這本書中提到htonl()函數的原型。實現代碼如下: long htonl(long value) {   return ((value <<24 )|((value<&

HDU acm 1003 Max Sum || 動態規劃求最大子序列

line namespace num more sequence mem ould 動態規劃 ger Max Sum Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot

Java設計模式之五大創建型模式(附實例

caf aac concrete 為什麽 ota pil sem 而不是 rtm 一、概況 總體來說設計模式分為三大類: (1)創建型模式,共五種:工廠方法模式、抽象工廠模式、單例模式、建造者模式、原型模式。 (2)結構型模式,共七種:適配器模式、裝飾器模式、代理模式

Android-基本控件四種布局方式

步驟 頁面 標示 string 過多 初始 contex 前端 size 轉自:https://www.cnblogs.com/ludashi/p/4883915.html 一、常用基本控件 1.TextView 看到Android中的TextView, 我不禁的想到

Nginx 服務器配置

proxy erer 模塊 了解 bin 變量 linux 系統 auto 參數 目錄 Nginx 服務器配置和詳解 Nginx 模板配置 Nginx 模塊說明 核心模塊 http 模塊 Nginx 服務器配置和詳解 Nginx 扮演 web 開發的服務端入口控制

轉載: Oracle 11g 集群介紹

rc4 blog lin 安裝 linux cnblogs 相關 erp .html 集群概念介紹(一)ORACLE集群概念和原理(二)RAC 工作原理和相關組件(三)緩存融合技術(四)RAC 特殊問題和實戰經驗(五)ORACLE 11 G版本2 RAC在LINUX上使用N

equals==

equals和==小結 1. ==簡單介紹 2. equals

Spring cloud系列九 Hystrix的配置屬性優先順序

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/hry2015/article/details/78554846 1. 概述 本文對Hystrix的配置引數的覆蓋優先順序,可配置引數的種類、配置項進行詳細的介紹。 Hystrix可以

Javascript中的 “&” “|”

  轉自:https://www.jb51.net/article/104394.htm 一、前言: 在文章開始之前,先出幾個題目給大家看看: var num1 = 1 &

程序執行緒的趣

程序(process)和執行緒(thread)是作業系統的基本概念,但是它們比較抽象,不容易掌握。 最近,我讀到一篇材料,發現有一個很好的類比,可以把它們解釋地清晰易懂。 1. 計算機的核心是CPU,它承擔了所有的計算任務。它就像一座工廠,時刻在執行。

StringBuffer類的使用底層實現、StringStringBuffer的區別、StringBuffer的常用方法

Java StringBuffer類的使用和詳解底層實現、String和StringBuffer的區別、StringBuffer的常用方法 1.java StringBuffer類 2. StringBuffer類的構造器(構造方法) 3.

二維字首

這幾天在打比賽時遇到了二維字首和,看了一下深有體會,發一篇詳解。 首先,什麼是字首和?一個數列,我們要計算某個區間內的和,該怎麼做呢?正所謂暴力出奇跡,這一個也可以,我們暴力列舉每一個區間內的數並且相加,可是這個是O(n)的時間複雜度,不要小看這個線性,可如果在

iForest的演算法原理

"An outlier is an observation which deviates so much from other observations as to arouse suspicions that it was generated by a different mechanis

C/C++ 的*&

C/C++ *和& 詳解 C/C++中 * 的用法 1>最簡單的乘法: a*b; 2>可以註釋: /**/ 3>指標:(最重要) 指標是指向變數的地址 簡單的例子分析: int main() { int a = 3; int *

docker的認識

docker認識與使用 1.docker簡介 什麼是容器? 一種虛擬化的方案,作業系統級別的虛擬化,只能執行相同或相似核心的作業系統 docker的容器技術依賴於linux核心特性:namespace和cgroups(control group),所

android 常用集合HashMap的使用

Java的集合類由Collection介面和Map介面派生 集合類的介面定義 1) Collection 一組"對立"的元素,每個位置只能儲存一個元素(物件),通常這些元素都服從某種規則   1.1) List必須保持元素特定的順序   1.2) Set

Android開發之基本控制元件四種佈局方式

Android中的控制元件的使用方式和iOS中控制元件的使用方式基本相同,都是事件驅動。給控制元件新增事件也有介面回撥和委託代理的方式。今天這篇部落格就總結一下Android中常用的基本控制元件以及佈局方式。說到佈局方式Android和iOS還是區別挺大的,在iOS中有F

Java中 ArrayList、VectorLinkedList 的使用(轉)

import java.util.*; /** * (1)ArrayList是最常用的List實現類,內部是通過陣列實現的,它允許對元素進行快速隨機訪問。陣列的缺點是每個元素之間不能含有“空隙”。 * 當陣列大小不滿足時會增加儲存能力,將已有陣

Android開發的之基本控制元件四種佈局方式

Android中的控制元件的使用方式和iOS中控制元件的使用方式基本相同,都是事件驅動。給控制元件新增事件也有介面回撥和委託代理的方式。今天這篇部落格就總結一下Android中常用的基本控制元件以及佈局方式。說到佈局方式Android和iOS還是區別挺大的,在iOS中有Frame絕對佈局和AutoL