socket编程中htonl和htons深入探讨

  • 背景:
  • 问题分析和解决:
  • 深入分析:

背景:

  在socket编程中遇到一个错误:server端设置端口和ip时,使用htonl函数。然后client死活无法连接,一致报错

connect error: Connection refused(errno:111)

问题代码:

serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htonl(6666);

问题分析和解决:

  刚开始,一再检查代码逻辑,也在网上找了一些资料,按照一些方法作了修改,但是问题依然无法解决。(其实是想偷懒。呵呵)
  后来将"htonl(666)"改为"htons(666)"程序运行正确了,client可以连接上。但是一直想不通为什么使用htonl不可以,非要使用htons呢。
  修改后的代码:

serveraddr.sin_addr.s_addr = htons(INADDR_ANY);
serveraddr.sin_port = htons(6666);    //unsigned short类型,即16位,因为端口一般的取值范围是0~65536

深入分析:

(1)为什么htons(6666)时,serveraddr.sin_port值为2586?

  经过gdb单步调试,发现使用htonl时候,serveraddr.sin_port的值为0,使用htons时候,serveraddr.sin_port的值为2586。

unsigned short类型的6666为10进制,用16进制表示为:0x1A0A,在机器(小端序)内存中存放顺序为0x0A 0x1A;十进制:unsigned 6666十六进制:0x1A0A,总共两个字节,高位字节为0x1A,低位字节为0x0A。主机CPU是小端序(大部分CPU都是小端序的,即低字节在前,高字节在后),内存里的顺序为:0x0A1A但是,经过htons转换后,高低字节变换了,变为大端序:0x0A1A,即A1A,对应十进制就是2586。此时,内存里的顺序(还是小端序的CPU)就成了:0X1A0A。由于转换后,内存里的值变了。打印出来自然就是不一样了(6666变成了2586)。

好了,这就理解了6666为什么经过htons转换后就成了2586。
(上面这一段也不知道怎么排版和调整字体才好看,就弄成这样了。。)
  
(2)为什么htonl(6666)时,serveraddr.sin_port值为0?
  接下来看看为什么使用htonl转换结果就是0呢?

十进制:unsigned int 6666,32位,4个字节十六进制:0x00001A0A,总共4个字节,高位字节--->低位字节依次是:0x00 0x00 0x1A 0x0A经htonl转换为大端序后为:0x0A 0X1A 0X00 0X00,即0x0A1A0000,对应十进制就是169476096。

  那么为什么serveraddr.sin_port值是0而不是169476096?
  前面说了,serveraddr.sin_port是unsigned short类型(可以在netinet/in.h或arpa/inet.h中查看)。unsigned short的范围是0~65535,很显然无法容纳169476096。

unsigned int: 16947609616进制:0x0A1A00002进制:0000 1010, 0001 1010, 0000 0000, 0000 0000将htonl(6666)的值(169476096)赋值给serveraddr.sin_port时候,由于serveraddr.sin_port是unsigned short类型,会进行隐式类型转换:
将unsigned int类型的169476096强转为unsigned short时,会做截断处理:
截掉了前面两个高位字节,剩下两个低位字节:0000 0000, 0000 0000 即为0,然后将该值赋给serveraddr.sin_por。所以gdb时候看到serveraddr.sin_por的值为0。但是使用%d单独printf输出htonl(6666)时候值为0。至于为什么截断高位字节,只保留低位字节,可能是C语言设计的处理规则吧。

现在两个问题已经搞明白了。还有一点提醒就是,

serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);    //unsigned int类型,即32位ip地址,这里将主机的无符号长整型数转换成网络字节顺序
// serveraddr.sin_addr.s_addr = htons(INADDR_ANY);    //也可以使用htonl替换htons,测试没发现报错,但是最好使用htonl,毕竟类型保持一致

  现在两个问题已经搞明白了。还有一点提醒就是:

serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);    //unsigned int类型,即32位ip地址,这里将主机的无符号长整型数转换成网络字节顺序
// serveraddr.sin_addr.s_addr = htons(INADDR_ANY);    //也可以使用htonl替换htons,测试没发现报错,但是最好使用htonl,毕竟类型保持一致

(3)端口说明:
  端口号:
  对于BSD:
  1-1023:BSD保留端口。
  1024-5000:BSD临时端口。
  5001-65535:BSD服务器(非特权)

socket编程中htonl和htons深入探讨相关推荐

  1. IP地址的三种表示格式及在Socket编程中的应用

    转自:http://blog.csdn.net/hguisu/article/details/7449955 使用TCP/IP协议进行网络应用开发的朋友首先要面对的就是对IP地址信息的处理.IP地址其 ...

  2. IP地址的三种表示格式 及 在Socket编程中的应用

    关于windows中的INADDR_ANY这个宏 头文件winsock.h中定义#define INADDR_ANY              (u_long)0x00000000 它是用于多IP机器 ...

  3. SOCKET编程中,select()函数的作用

    SOCKET编程中,select()函数的作用Select在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect.accep ...

  4. socket编程中常见的概念问题!

    socket编程一般指的就是网络编程,常见的服务端和客户机都是必不可少的,今天小千就来给大家介绍一下socket编程中常见的概念问题. 一.常见传输协议 1.tcp协议 TCP (Transmissi ...

  5. socket编程中read()、write()、recv()和send()

    ​​​​​​Muduo 网络编程示例之八:用 Timing wheel 踢掉空闲连接 - 陈硕 - 博客园socket编程中read().write().recv()和send()的区别_John W ...

  6. TCP与UDP在socket编程中的区别

    TCP与UDP在socket编程中的区别 一.TCP与UDP的区别 基于连接与无连接 对系统资源的要求(TCP较多,UDP少) UDP程序结构较简单 流模式与数据报模式 TCP保证数据正确性,UDP可 ...

  7. C语言socket编程中关于read()和write()的思考

    最近开始学习C的socket编程,教材上有一处依照我对IO函数的理解,我感觉有点问题,故而研究了一下.学的很浅,可能有错漏. 1.socket编程中read()和write()内部原理 每个socke ...

  8. TCP的socket编程中“全双工的字节流”含义的深刻理解

    本人从事TCP的socket编程多年,趟过很多坑,对于TCP是"全双工的字节流"这几个字的含义有深刻理解.这几个字,文字虽少,但字字精辟.如果没有深刻理解,编程中可能知其然不知其所 ...

  9. socket编程中的 htons()

    文章目录 1.内存存储数据的方式 1.1 数据字节序号 1.2 小端字节序 1.3 大端字节序 2. 转换顺序 2.1 网络字节序 2.2 主机字节序 2.3 转换函数   在刚刚接触 socket ...

最新文章

  1. 数据的存入取出(注册机方式)
  2. 用python写一个简单的爬虫_Python实现简易Web爬虫详解
  3. 1.Hadoop初步环境搭建(ssh无密码通信)
  4. Linux文件系统映像:Initranfs 和 Initrd
  5. 七大排序算法的个人总结(二)
  6. 网站打开速度多少毫秒为正常_诠网科技|网站优化中跳出率多少才是合理的?...
  7. python调用其他文件中的函数或者类
  8. android sdio 时钟 ios-clock,iOS 炫酷时钟
  9. c# redis 如何设置过期时间_Redis 过期时间与内存管理
  10. python中常见的运行时错误_新手常见Python运行时错误汇总
  11. angular ts 表格_angular+ng-zorro路由、表格组件
  12. C++11 修复了双重检查锁定问题(转)
  13. 在线火星文转换器工具
  14. linux内存手动释放
  15. FileZilla Server目录显示失败的处理方法
  16. HDU 5773 (DP)
  17. 华为系统和计算机,电脑手机合二为一 华为多屏协同让电脑与手机亲密互动
  18. mysql大于等于between比较_MySQL范围查询优化,Between与大于等于对比及优化
  19. Unity中加载倾斜摄影模型、dem叠加卫星影像做真实地形
  20. C语言实现复数计算器

热门文章

  1. 朴素贝叶斯分类算法分析与实践
  2. matlab绘制二次曲线,并找出最大值位置(找出两曲线的最大差值点)
  3. 模板引擎FreeMarker的介绍和使用
  4. c语言编程ad7799,51单片机驱动AD7799程序(keil c)
  5. 独立站卖家如何使用 WhatsApp Business API 建立有意义的客户关系?
  6. 信息时代的智慧——兼谈科普转发
  7. VIEWGOOD(远古)数字化校园建设的应用方案
  8. 看一遍就懂,详解java多线程——volatile
  9. C# 文本框只能输入数字和退格键
  10. Python实现带南海九段线分位数地图完整可视化版本(附代码及数据)