分享

网络编程相关【源自多处网络博客,未整理】

 xinyz4104 2014-09-25

inet_addr 将"数字+句点"的格式的IP地址转换到unsigned long中,返回值已经是按照网络字节顺序的
相反inet_ntoa把类型为struct in_addr的数据转化为"数字+句点"的形式的字符串
typedef u_int32_t in_addr_t;
struct in_addr
{
       in_addr_t s_addr;
};

本机字节顺序与网络字节顺序的转换
#include <arpa/inet.h>
htons  ------"host to network short"
htonl   -------"host to network long"
ntohs  -------"network to host short"
ntohl   -------"network to host long"
*注意:在你的数据放到网络上的时候,确信它是网络字节顺序
网络字节顺序(大端字节)和x86机器字节顺序(小端字节)
eg:0X3132  在x86上显示21  在网络传输中为12

inet_addr返回的整数形式是网络字节序,而inet_network返回的整数形式是主机字节序。他俩都有一个小缺陷,
那就是当IP是255.255.255.255时,这两个函数会认为这是个无效的IP地址,这是历史遗留问题,其实在目前大部
分的路由器上,这个255.255.255.255的IP都是有效的。
inet_aton函数和上面这俩个函数的区别就是在于他认为255.255.255.255是有效的,他不会冤枉这个看似特殊的IP地址。对了,inet_aton函数返回的是网络字节序的IP地址。

综上所述,应该使用inet_aton和inet_ntoa这一对函数。


资料:

#include <sys/socket.h>
#include 
<netinet/in.h>
#include 
<arpa/inet.h>

typedef uint32_t in_addr_t;

int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(
const char *cp);
in_addr_t inet_network(
const char *cp);
char *inet_ntoa(struct in_addr in);
struct in_addr inet_makeaddr(int net, int host);
in_addr_t inet_lnaof(
struct in_addr in);
in_addr_t inet_netof(
struct in_addr in);


 

// Internet address.
struct in_addr {
        union {
                
struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
                
struct { u_short s_w1,s_w2; } S_un_w;
                u_long S_addr; 
/* port in network byte order */
        } S_un;
#define s_addr  S_un.S_addr
};
// Socket address, internet style.
struct sockaddr_in {        // struct sockaddr的一种特殊形式
        short            sin_family;    /* address family: AF_INET */
        u_short        sin_port;        
/* port in network byte order */
        
struct in_addr sin_addr;        /* port in network byte order */
        
char            sin_zero[8];    /* 8 byte pad */
};
// Structure used by kernel to store most addresses.
struct sockaddr {
        u_short sa_family; 
/* address family */
        
char    sa_data[14]; /* up to 14 bytes of direct address */
};

struct in_addr {
    unsigned 
long int s_addr;
}


  sockaddr结构体
sockaddr的缺陷:sa_data把目标地址和端口信息混在一起了

struct sockaddr {  
     unsigned short sa_family;
   char sa_data[14];                  
   }; 
sa_family是通信类型,最常用的值是 "AF_INET"
sa_data14字节,包含套接字中的目标地址和端口信息

  
   sockaddr_in 结构体
sockaddr_in结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中
struct sockaddr_in { 
   short int sin_family;
   unsigned short int sin_port; 
     struct in_addr sin_addr;
struct in_addr { 
    unsigned long s_addr;
           }
                
     unsigned char sin_zero[8];
 

   sin_port和sin_addr都必须是NBO
一般可视化的数字都是HBO(本机字节顺序)


    sin_zero 初始值应该使用函数 bzero() 来全部置零。
   一般采用下面语句
struct sockaddr_in cliaddr;
bzero(&cliaddr,sizeof(cliaddr));
  

   sockaddr_in结构体变量的基本配置
struct sockaddr_in ina;

bzero(&ina,sizeof(ina));

ina.sin_family=AF_INET;

ina.sin_port=htons(23);
ina.sin_addr.s_addr = inet_addr("132.241.5.10");  


    sockaddr 和 sockaddr_in的相互关系
一般先把sockaddr_in变量赋值后,强制类型转换后传入用sockaddr做参数的函数

  •     sockaddr_in用于socket定义和赋值
  •     sockaddr用于函数参数


   最典型的源、目的节点socket定义
对于源、目的地址和源、目的地址端口,需要建立两个socket变量
cliaddr绑定源地址和源端口
servaddr用于connect和sendto的设定目的地址和目的端口

struct sockaddr_in servaddr,cliaddr;

create_socket(char *server_addr_string,unsigned int server_port)
{
源socket赋值
       bzero(&cliaddr,sizeof(cliaddr));
       cliaddr.sin_family = AF_INET;
       通常TCP/UDP 协议源地址和端口都是随机的
       cliaddr.sin_addr.s_addr = htons(INADDR_ANY);
       cliaddr.sin_port = htons(0);

目的socket赋值
       bzero(&servaddr,sizeof(servaddr));
       servaddr.sin_family = AF_INET;
       inet_aton(server_addr_string,&servaddr.sin_addr);
       servaddr.sin_port = htons(server_port);
}


    网络字节顺序 (Network Byte Order)      NBO
结构体的sin_port和sin_addr都必须是NBO

   本机字节顺序 (Host Byte Order)    HBO
一般可视化的数字都是HBO

    NBO,HBO二者转换
inet_addr()    将字符串点数格式地址转化成无符号长整型(unsigned long s_addr s_addr;)
inet_aton()    将字符串点数格式地址转化成NBO
inet_ntoa ()     将NBO地址转化成字符串点数格式
htons()    "Host to Network Short"
htonl()    "Host to Network Long"
ntohs()    "Network to Host Short"
ntohl()    "Network to Host Long"
常用的是htons(),inet_addr()正好对应结构体的端口类型和地址类型

    三种给socket赋值地址的方法
inet_aton(server_addr_string,&myaddr.sin_addr);
myaddr.sin_addr.s_addr = inet_addr("132.241.5.10");
INADDR_ANY转不转NBO随便
myaddr.sin_addr.s_addr = htons(INADDR_ANY);  
myaddr.sin_addr.s_addr = INADDR_ANY;


    两种给socket 赋值端口的方法
#define MYPORT 3490 
myaddr.sin_port = htons(MYPORT);
0(随机端口)转不转NBO随便
myaddr.sin_port = htons(0);
myaddr.sin_port = 0;  


    htons/l和ntohs/l等数字转换都不能用于地址转换,因为地址都是点数格式,所以地址只能采用数字/字符串转换如inet_aton,inet_ntoa;
唯一可以用于地址转换的htons是针对INADDR_ANY
 cliaddr.sin_addr.s_addr = htons(INADDR_ANY)

   inet_addr()与inet_aton()的区别

  •     inet_addr()    是返回值型

struct sockaddr_in ina;

ina.sin_addr.s_addr = inet_addr("132.241.5.10"); 

  •     inet_aton()     是参数指针型
struct sockaddr_in ina;

inet_aton("132.241.5.10",&ina.sin_addr);


   inet_ntoa  将NBO地址转化成字符串点数格式
参数:结构体变量.sinaddr
返回值:字符串指针
a1 = inet_ntoa(ina.sin_addr);
printf("address 1: %s\n",a1); 
address 1: 132.241.5.10 


    inet_addr()的缺陷:必须对-1做检测处理
因为inet_addr()的结果是整型,而发生错误时返回-1。
而 ina.sin_addr.s_addr是unsigned long型
-1在long short显示成111111111,和IP地址255.255.255.255相符合!会被误认为广播地址!



今天在网上看到一篇关于htonl()函数的解释,感觉有道理,贴过来大家一起学习!微笑

htonl就是把本机字节顺序转化为网络字节顺序

h---host 本地主机
to  就是to 了
n  ---net 网络的意思
l 是 unsigned long

所谓网络字节顺序(大尾顺序)就是指一个数在内存中存储的时候“高对低,低对高”(即一个数的高位字节存放于低地址单元,低位字节存放在高地址单元中)。但是计算机的内存存储数据时有可能是大尾顺序或者小尾顺序。

先举个例子:
int a = 0x403214;
int b = htonl(a);
我在VC++6.0调试这段代码,发现
&a的值为:0x0012ff44
其中0x0012ff44、0x0012ff45、0x0012ff46、0x0012ff47这四个单元的值依次为:14、32、40、00,即0x403214这个数的高位部分存放在高位地址中,低位部分存放在低位地址中,即小尾顺序。
&b的值为:0x0012ff40
其中0x0012ff40、0x0012ff41、0x0012ff42、0x0012ff43这四个单元的值依次为:00、40、32、14,即把原数0x403214的高位部分存放在低位地址中,低位部分存放在高位地址中。
由此可见,如果一个数以小尾顺序存储,经htonl函数调用后这个数的高地位字节会完全颠倒过来成为一个新的数。这个新的数在机器内部其实还是以小尾顺序存储的,但是相对于原来的数而言相当于是变成大尾顺序的了。
long型的0x40写完整为:0x 00 00 00 40,共四个字节,调用htonl后四个字节颠倒顺序,为0x 40 00 00 00。
同样,0x40 00 00 00调用htonl后变为0x 00 00 00 40,即0x40


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多