Linux网络编程基础API-socket地址API-1.1

一、主机字节序和网络字节序

1、字节序分为大端字节序(big endian)和小端字节序(littl endian):

  • 大端字节序:一个整数的高位字节(23~31bit)存储在内存的低地址处,低位字节(0~7bit)存储在内存的高地址处;
  • 小端字节序:一个整数的低位字节存储在内存的低地址处,高位字节存储在内存的高地址处。

2、现代PC大多采用小端字节序,小端字节序也称为主机字节序;

   因为发送端和接收端使用的标准可能不同,所以需要发送端先转换为大端字节序然后发送,大端字节序也成为网络字节序。

   即使是同一机器上的两个进程(如c和java编写的程序),也要考虑字节序的问题。

3、Linux提供的主机字节序和网络字节序之间的转换:

#include <netinet/in.h>
unsigned long int htonl( unsigned long int hostlong);
unsigned short int htons( unsigned short int hostshort );
unsigned long int ntohl( unsigned long int netlong);
unsigned short int ntohs( unsigned short int netshort );

 htonl表示“host to network long”,其他同理;长整型(long)通常是IP,短整型(short)通常是端口号。

二、通用socket地址

 socket网络编程接口中表示scket地址的是结构体sockaddr:

#include <bits/socket.h>
struct sockadd
{
    sa_family_t  sa_family; /*sa_family_t是地址族类型,协议族类型通常和地址族类型对应*/
    char sa_data[14];/*sa_data用于存放socket地址值,注意 不同协议族的长度不同*/
};

协议族和协议族的关系:

协议族及其地址值:

 由上表可见14字节的sa_data根本无法容纳多数协议族的地址值,故linux定义了下面的这个通用结构体:

#include <bits/ socket .h>
struct sockaddr_ storage
{
    sa_ family_ t sa_ family;
    unsigned long int   __ss_ align;
    char  __ss_ padding[128-sizeof (__ ss_ align )] ;
}

三、专用socket地址

UNIX本地域协议族专用结构体:

include <sys/un.h>
struct sockaddr_ un
{
    sa_family_t sin_family; /* 地址族:AF_UNIX */
    char sun_path[108];    /* 文件路径名 */
}

TCP/IP协议族的专用socket结构体:

struct sockaddr_ in
{ 
    sa_ family_ t  sin_family;  /*地址族; AF_ INET */
    u_int16_ t  sin_port;         /*端口号,要用网络字节序表示*/
    struct in_addr  sin_addr;   /* 1PV4地址结构体,见下面*/
};

struct in_ addr
    u_int32_ t  s_addr; /* IPv4 地址,要用网络宇节序表示*/
};

struct sockaddr_in6
{
    sa_family_t  sin6_family;/*地址族: AF_ INET6 */
    u_int16_t sn6_t   sin6_port;/*端口号,要用网络字节序表示*/
    u_int32_t sn6_t   flowinfo;/*流信息,应设置为0 */
    struct in6_addr sin6_addr;/* IPv6地址结构体,见下面*/
    u_int32_t sin6_scope_id;/* scope ID, 尚处于实验阶段*/
};

struct in6_ addr
{
    unsigned char sa_ addr[16] ;/* IPv6地址, 要用网络字节序表示*/

};

所有专用socket地址类型变量在实际使用时都需要转换为sockadd_storage,因为所有socket编程接口使用的地址参数都是sockaddr。

四、IP地址转换函数

1、 IPv4地址和用网络字节序整数表示的IPv4地址之间转换:

#include <arpa/inet.h>
in_addr_t inet_addr ( const char* strptr );
int inet_aton( const char* cp,  struct in_addr* inp ) ;
char*  inet_ntoa( struct in_addr in );

inet_addr:IPv4的点分十进制 转换为 网络字节序整数,失败返回INADDR_NONE;

inet_aton:和inet_addr结果一致,但转化结果存储在参数inp指向的地址结构中;

inet_ntoa:网络字节序整数 转换为 IPv4的点分十进制地址。

ps:inet_ntoa函数不可重入

2、适用于IPv4和IPv6的函数

#include <arpa/inet.h>
int inet_pton( int af, const char* src, void* dst );
const char* inet_ntop( int af, const void* src, char* dst, socklen_t cnt );

inet_pton:字符串表示的IP地址 src 转换成 网络字节序整数表示的IP地址;

inet_ntop:相反的转换,最后一个cnt参数是指定目标存储单元大小的,下方两个宏帮助程序员指定这个大小:

#include <netinet/in.h>
#define INET_ADDRSTRLEN 16
#define INET6_ADDRSTRLEN 46

inet_ntop成功时返回目标存储单元的地址,失败返回NULL 并设置error。

 

posted @ 2022-04-02 21:39  NK-cat  阅读(47)  评论(0编辑  收藏  举报