socket编程中的 htons()


  在刚刚接触 socket 时,遇到了 htons() 函数,就直接懵逼了,这是什么东西,有什么用?就查了一些资料。

  htons() 是网络字节序与主机字节序之间转换的函数。用生活中的例子来说,有一串数字 12345678 现在我们是从左往右读的,以前的人是从右往左读的。当你要给以前的人读的话就要把这串数据写成 87654321 。htons() 就是类似要完成这个转换的功能

1.内存存储数据的方式

  大于一个字节的数据在内存中有存放的顺序,一个字节的数据没有顺序的问题。存放的顺序就叫做字节顺序。

  那么在内存中存放大于一个字节的数据的方式有哪些?或者说顺序有哪些。内存中存储的方法有两种:小端字节序(little-endian)和大端字节序(big-endian)。

1.1 数据字节序号

  低序字节,就是一个数据的低序号字节。比如说一个数据是这样的 0x12345678 ,它是一个32位(4个字节)的整数数据。就是把这个数据放在4个字节里面。如下图
在这里插入图片描述
  12 是放在第一个字节里面的,第一个字节是高序号。第二个,第三个,第四个字节的序号依次降低。存放 78 的字节是最低序号。

1.2 小端字节序

  小端字节序——将低序字节存储在内存起始地址。用这个数据来说就是先存 78 ,然后存 56 ,接着存 34 ,最后存12。

在这里插入图片描述
在这里插入图片描述

1.3 大端字节序

  先将高序号的字节数据存入内存的起始地址。12 是存在高序号的字节里面,先将 12 存入内存的起始位置,接着是 34 ,56 ,78。
在这里插入图片描述

2. 转换顺序

  这两种字节序之间没有标准可循,两种格式都有系统使用。比如,Inter x86、ARM核采用的是小端模式,Power PC、MIPS UNIX和HP-PA UNIX采用大端模式。

2.1 网络字节序

  网络字节序:网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节序采用大端(big endian)排序方式。

2.2 主机字节序

  主机字节序:不同的机器主机字节序不相同,与CPU设计有关,数据的顺序是由cpu决定的,而与操作系统无关。

2.3 转换函数

  由于不同的机器主机字节序不同原因不同体系结构的机器之间无法通信,所以要转换成一种约定的字节序,也就是网络字节序即使是同一台机器上的两个进程(比如一个由C语言,另一个由Java编写)通信,也要考虑字节序的问题(JVM采用大端字节序)。

  网络字节序与主机字节序之间的转换函数: htons()…ntohs)…htonl()、ntohl).htons和ntohs完成16位无符号数的相互转换,htonl和ntohl完成32位无符号数的相互转换。host to network short long

  • 20
    点赞
  • 122
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
适合初学者 /******* 服务器程序 (server.c) ************/ #include <stdlib.h>; #include <stdio.h>; #include <errno.h>; #include <string.h>; #include <netdb.h>; #include <sys/types.h>; #include <netinet/in.h>; #include <sys/socket.h>; int main(int argc, char *argv[]) { int sockfd,new_fd; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int sin_size,portnumber; char hello[]="Hello! Are You Fine?\n"; if(argc!=2) { fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1); } if((portnumber=atoi(argv[1]))<0) { fprintf(stderr,"Usage:%s portnumber\a\n",argv[0]); exit(1); } /* 服务器端开始建立socket 描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"Socket error:%s\n\a",strerror(errno)); exit(1); } /* 服务器端填充 sockaddr 结构 */ bzero(&server_addr,sizeof(struct sockaddr_in)); server_addr.sin_family=AF_INET; server_addr.sin_addr.s_addr=htonl(INADDR_ANY); server_addr.sin_port=htons(portnumber); /* 捆绑sockfd 描述符 */ if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))== -1) { /******* 客户端程序 client.c ************/ #include <stdlib.h>; #include <stdio.h>; #include <errno.h>; #include <string.h>; #include <netdb.h>; #include <sys/types.h>; #include <netinet/in.h>; #include <sys/socket.h>; int main(int argc, char *argv[]) { int sockfd; char buffer[1024]; struct sockaddr_in server_addr; struct hostent *host; int portnumber,nbytes; if(argc!=3) { fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]); exit(1); } if((host=gethostbyname(argv[1]))==NULL) { fprintf(stderr,"Gethostname error\n"); exit(1); } if((portnumber=atoi(argv[2]))<0) { fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]); exit(1); } /* 客户程序开始建立 sockfd 描述符 */ if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"Socket Error:%s\a\n",strerror(errno)); exit(1); } /* 客户程序填充服务端的资料 */ bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(portnumber); server_addr.sin_addr=*((struct in_addr *)host->;h_addr); /* 客户程序发起连接请求 */ if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr) )==-1) { fprintf(stderr,"Connect Error:%s\a\n",strerror(errno)); exit(1); } /* 连接成功了 */ if((nbytes=read(sockfd,buffer,1024))==-1) { fprintf(stderr,"Read Error:%s\n",strerror(errno)); exit(1); } buffer[nbytes]='\0'; printf("I have received:%s\n",buffer); /* 结束通讯 */ close(sockfd); exit(0); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值