详解C语言的htons函数

在Linux和Windows网络编程时需要用到htons和htonl函数,用来将主机字节顺序转换为网络字节顺序。

在Intel机器下,执行以下程序

int main()
{
   printf("%d /n",htons(16));

return 0;
}

得到的结果是4096,初一看感觉很怪。

解释如下,数字16的16进制表示为0x0010,数字4096的16进制表示为0x1000。 由于Intel机器是小尾端,存储数字16时实际顺序为1000,存储4096时实际顺序为0010。因此在发送网络包时为了报文中数据为0010,需要经过htons进行字节转换。如果用IBM等大尾端机器,则没有这种字节顺序转换,但为了程序的可移植性,也最好用这个函数。

另外用注意,数字所占位数小于或等于一个字节(8 bits)时,不要用htons转换。这是因为对于主机来说,大小尾端的最小单位为字节(byte)。

什么是大端模式(big-endian),为什么使用大端模式(big-endian)。

uint16_t htons(uint16_t hostshort);
  htons的功能:将一个无符号短整型数值转换为网络字节序,即大端模式(big-endian)
  参数u_short hostshort: 16位无符号整数
  返回值:TCP / IP网络字节顺序
  htons 是把你机器上的整数转换成“网络字节序”, 网络字节序是 big-endian,也就是整数的高位字节存放在内存的低地址处。 而我们常用的 x86 CPU (intel, AMD) 电脑是 little-endian,也就是整数的低位字节放在内存的低字节处。举个例子吧。假定你的port是0x1234,在网络字节序里 这个port放到内存中就应该显示成addr addr+1,也就是:0x12 0x34;而在x86电脑上,0x1234放到内存中实际是:addr addr+1,也就是:0x34 0x12。htons 的用处就是把实际内存中的整数存放方式调整成“网络字节序”的方式。

第一个问题:为什么使用两个字节,也就是16位来存储。

  这个简单一些,因为一个字节只能存储8位2进制数,而计算机的端口数量是65536个,也就是2^16,两个字节。

第二个为题:为什么计算机需要大端模式和小端模式?

  小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
  大端模式 :符号位的判定固定为第一个字节,容易判断正负。

big endian:大尾端,也称大端(高位)优先存储。

little endian:小尾端,也称小端(低位)优先存储。

如下00000000 00000000 00000000 00000001的存储

大尾端: 00000000 00000000 00000000 00000001

addr+0    addr+1     addr+2   addr+3     //先存高有效位(在低地址)

小尾端: 00000001 00000000 00000000 00000000

addr+0    addr+1     addr+2   addr+3     //先存低有效位(在低地址)

故要判断机器的体系结构是大尾端还是小尾端,以下程序可以完成任务:


#include <stdio.h>
int main()
{
    int tt = 1;
    char *c = (char*)(&tt);
    if(*c == 1)
    {
        printf("litte endian\n");
    }
    else
    {
        printf("big endian\n");
    }
    return 0;
}

大小尾端数据间的相互转换

/*
      usage: to convert between the form of big-endian and little-endian
      author: ydzhang
      date: 2008年12月6日20:23:48
*/
#include <stdio.h>
typedef unsigned int u32;
typedef unsigned short u16;

#define BSWAP_16(x) \
        (u16) ( ((((u16)(x) & 0x00ff)) << 8) \
        | (((u16)(x) & 0xff00) >> 8) )

u16 bswap_16(u16 x)
{
    return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
}

u32 bswap_32(u32 x)
{
    return ((x & 0x000000ff) << 24) |
           ((x & 0x0000ff00) << 8) |
           ((x & 0x00ff0000) >> 8) |
           ((x & 0xff000000) >> 24);
}

int main()
{
     u16 num_16 = 0x1234;
     u32 num_32 = 0x12345678;

printf("%x\n", bswap_16(num_16));
    printf("%x\n", BSWAP_16(num_16));
    printf("%x\n", bswap_32(num_32));
    return 0;
}

时间: 2024-10-12 22:52:12

详解C语言的htons函数的相关文章

详解C语言的main函数

如图所示:#include<stdio.h>这是一个头文件,包含的是C程序运行的C语言的库函数,只有包含了相关的头文件,在程序中才能调用.stdio表示输入输出控制.printf():就是来自这个头文件. int main(int argc ,const char *argv[]){...} :int 表示函数的返回值类型,main是函数名, ()里面的是参数,前面的关键字标示的是参数的类型 ,argc是命令行中的参数的个数,argv[]对应每一个参数. return是一个函数的返回值,当函数

详解go语言的array和slice 【二】

上一篇  详解go语言的array和slice [一]已经讲解过,array和slice的一些基本用法,使用array和slice时需要注意的地方,特别是slice需要注意的地方比较多.上一篇的最后讲解到创建新的slice时使用第三个索引来限制slice的容量,在操作新slice时,如果新slice的容量大于长度时,添加新元素依然后使源的相应元素改变.这一篇里我会讲解到如何避免这些问题,以及迭代.和做为方法参数方面的知识点. slice的长度和容量设置为同一个值 如果在创建新的slice时我们把

jQuery选择器代码详解(七)——elementMatcher函数

要读懂Sizzle的Compile执行过程,首先需要弄清楚涉及的各个子程序的功能和关键变量和作用,我将逐一对jQuery-1.10.2版本的Compile代码进行说明,望能给予大家帮助. elementMatcher(matchers) 1.源码 function elementMatcher(matchers) { return matchers.length > 1 ? function(elem, context, xml) { var i = matchers.length; while

jQuery选择器代码详解(八)——addCombinator函数

function addCombinator(matcher, combinator, base) 1.源码 function addCombinator(matcher, combinator, base) { var dir = combinator.dir, checkNonElements = base && dir === "parentNode", doneName = done++; return combinator.first ? // Check a

举例详解Python中的split()函数的使用方法

这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下 函数:split() Python中有split()和os.path.split()两个函数,具体作用如下:split():拆分字符串.通过指定分隔符对字符串进行切片,并返回分割后的字符串列表(list)os.path.split():按照路径将文件名和路径分割开 一.函数说明1.split()函数语法:str.

详解php 获取文件名basename()函数的用法

PHP 中basename()函数给出一个包含有指向一个文件的全路径的字符串,此函数返回基本的文件名,本篇文章收集了关于使用PHP basename()函数获取文件名的几篇文章,希望对大家理解使用PHP basename()函数获取文件名有所帮助. 1.详解php basename()函数获取文件名的用法 php basename()函数给出一个包含有指向一个文件的全路径的字符串,本函数返回基本的文件名.如果文件名是以 suffix 结束的,那这一部分也会被去掉.在 Windows 中,斜线(/

http标头详解/即php中header函数应用解释

HTTP协议header标头详解 分类: Webkit Web Php C/C++ 2012-10-31 11:19 14366人阅读 评论(0) 收藏 举报 本文根据RFC2616(HTTP/1.1规范),参考 http://www.w3.org/Protocols/rfc2068/rfc2068 http://www.w3.org/Protocols/rfc2616/rfc2616 http://www.ietf.org/rfc/rfc3229.txt 通常HTTP消息包括客户机向服务器的请

oracle分析函数技术详解(配上开窗函数over())

一.Oracle分析函数入门 分析函数是什么?分析函数是Oracle专门用于解决复杂报表统计需求的功能强大的函数,它可以在数据中进行分组然后计算基于组的某种统计值,并且每一组的每一行都可以返回一个统计值. 分析函数和聚合函数的不同之处是什么?普通的聚合函数用group by分组,每个分组返回一个统计值,而分析函数采用partition by分组,并且每组每行都可以返回一个统计值. 分析函数的形式分析函数带有一个开窗函数over(),包含三个分析子句:分组(partition by), 排序(or

malloc函数详解 C语言逻辑运算符

今天写线性表的实现,又遇到了很多的难题,C语言的指针真的没学扎实.很多基础都忘了. 一是 :malloc 函数的使用. 二是:C语言逻辑运算符. 一.原型:extern void *malloc(unsigned int num_bytes); 头文件:#include <malloc.h> 或 #include <alloc.h> (注意:alloc.h 与 malloc.h 的内容是完全一致的.) 功能:分配长度为num_bytes字节的内存块 说明:如果分配成功则返回指向被分