网络地址adderss相关操作

网络地址adderss


Berkeley套接字接口拟定了一个通用套接字地址结构sockaddr,用于表示任意类型的地址,所有的套接字API在传入地址参数时都只需要传入sockaddr类型,以保证接口的通用性。除通用地址结构sockaddr外,还有一系列表示具体的网络地址的结构,这些具体的网络地址结构用于用户赋值,但在使用时,都要转化成sockaddr的形式。

sockaddr表示通用套接字地址结构,其定义如下:

struct sockaddr
{
    unsigned short sa_family; // 地址族,也就是地址类型
    char sa_data[14];         // 地址内容
};

所有的套接字API都是以指针形式接收sockaddr参数,并且额外需要一个地址长度参数,这可以保证当sockaddr本身不足以容纳一个具体的地址时,可以通过指针取到全部的内容。比如上面的地址内容占14字节,这并不足以容纳一个128位16字节的IPv6地址。但当以指针形式传入时,完全可以通过指针取到适合IPv6的长度。

/*
当你将一个uint32_t类型的IP地址转换为sockaddr_in结构体时,通常需要考虑字节序问题。
在IPv4中,地址通常以点分十进制表示(如"192.168.0.1"),在内存中存储时则转换为一个32位的整数。
然而,不同的系统可能有不同的字节序,大端法(Big-Endian)和小端法(Little-Endian)。
*/
struct sockaddr_in
{
    unsigned short sin_family; // 地址族,IPv4的地址族为AF_INET
    unsigned short sin_port;   // 端口
    struct in_addr sin_addr;   // IP地址,IPv4的地址用一个32位整数来表示
    char sin_zero[8];          // 填充位,填零即可
};

typedef uint32_t in_addr_t;
struct in_addr
{
    in_addr_t s_addr;
};
 
struct sockaddr_in6
{
    unsigned short sin6_family; // 地址族,IPv6的地址族为AF_INET6
    in_port_t sin6_port;        // 端口
    uint32_t sin6_flowinfo;     // IPv6流控信息
    struct in6_addr sin6_addr;  // IPv6地址,实际为一个128位的结构体
    uint32_t sin6_scope_id;     // IPv6 scope-id
};
 
struct sockaddr_un
{
    unsigned short sun_family;  // 地址族,Unix域套字地址族为AF_UNIX
    char sun_path[108];         // 路径字符串
};

getsockname getpeername

getsockname 返回与某个套接字关联的本地协议地址
getpeername 返回与某个套接字关联的外地协议地址

int getsockname (int sockfd, struct sockaddr * localaddr, socklen_t addrlen);
int getsockname (int sockfd, struct sockaddr * peerladdr, socklen_t addrlen);

这两个函数都装填由localaddr或peerladdr指针所指的套接字地址结构,协议地址返回到这里
输出 成功为0 , 出错则为-1

gethostbyname

返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针

struct hostent *gethostbyname(const char * hostname);

返回值的结构体:
struct hostent
{
    char FAR * h_name;
    char FAR * FAR * h_aliases;
    short h_addrtype;
    short h_length;
    char FAR * FAR * h_addr_list;
};

h_name成员是我们正在查询的主机的官方名字。也就是主机的权威名字。如果我们提供了一个别名,或是不带域名的主机名,那么这个成员就会描述我们要查询的正确名字
h_aliases成员是我们查询的主机名的别名数组。这个列表的结尾被标记为NULL指针
在成员h_addrtype中返回的值为AF_INET。然而,因为IPv6已经完全实现,名字服务器也会返回IPv6地址。当这种情况发生时,h_addrtype就会在合适的时候返回AF_INET6。
h_addrtype值的上的就是表明在列表h_addr_list中的地址格式
h_length成员这个值与h_addrtype成员相关。对于当前的TCP/IP协议版本(IPv4),这个成员的值总是为4,表明4个字节的IP地址。然而,当IPv6实现时,这个值将会是16,并且返回IPv6地址
h_addr_list成员当执行一个名字到IP地址的转换时,这个成员就会成为我们最重要的信息。当h_addrtype成员包含AF_INET时,这个数组中的每一个指针指向一个4字节的IP地址。这个列表的结尾被标记为NULL指针
返回 :成功时为非空指针,出错则为NULL且设置h_errno

gethostbyaddr

由一个二进制的IP地址找到主机名,与gethostbyname恰好相反

struct hostent *gethostbyaddr(const char * addr , socklen_t len , int family);

len为addr大小,family为协议族
返回 :成功时为非空指针,出错则为NULL且设置h_errno

getservbyname getservbyport

如果我们在代码中通过其名字而不是端口号来指代一个服务,而且从名字到端口号的映射关系保存在一个文件中,那么即使端口号发生变动我们修改那个映射文件即可,而不必重新编译程序
getservbyname用于根据给定名字查找相应的端口
getservbyport用于根据端口号和可选协议查找相应服务

struct servent *getservbyname(const char * servname , const char *protoname);
struct servent *getservbyport(int port , const char *protoname)

返回值的结构体:
struct servent{
    char *s_name; //正式名称
    char **s_aliases; //别名
    int s_port; //端口号
    char *s_proto; //协议
}

servname服务名
port端口号
protoname为可选协议
返回 :成功时为非空指针,出错则为NULL

getaddrinfo

gethostbyname和getservbyname只适用于IPv4
getaddrinfo可以IPv4和IPv6,能够处理名字到地址以及服务到端口这两种转换

int getaddrinfo(const char *hostname, const char *service,const struct addrinfo *hints, struct addrinfo **result);

通过result指针返回一个指向addrinfo结构链表的指针
struct addrinfo {
    int ai_flags;   /* 标志位 */
    int ai_family;    /* 协议族: AF_INET|AF_INET6|AF_UNSPEC... */
    int ai_socktype;    /* sock类型: SOCK_DGRAM|SOCK_STREAM */
    int ai_protocol;    /* 协议类型: IPPROTO_TCP|IPPROTO_UDP... */
    socklen_t ai_addrlen;   /* 地址结构长度 */
    char *ai_canonname; /* host的正式名称 */
    struct sockaddr *ai_addr;   /* 地址结构 */
    struct addrinfo *ai_next;   /* result是个链表结构,ai_next指向下一个addrinfo */
}

ai_flags:
1)AI_ADDRCONFIG: 只有当本地主机被配置为IPv4时,getaddrinfo返回IPv4地址,IPv6同理。
2)AI_CANONNAME: ai_canonname默认为NULL,设置此标志位,告诉getaddrinfo将列表中第一个addrinfo结构体的ai_cannoname字段指向host的权威(官方)名字。
3)AI_NUMERICSERV: service默认为服务名或端口号。这个标志强制参数service为端口号。
4)AI_PASSIVE: getaddrinfo默认返回套接字地址,客户端可以在调用connect时用作主动套接字。此标志位告诉该函数,返回的套接字地址可能被服务器用作监听套接字。此时,host应该为NULL5)AI_NUMERICHOST:用于指示getaddrinfo函数在解析主机名时是否进行名称解析。当我们需要使用IP地址而不是主机名来创建套接字时,可以将AI_NUMERICHOST常量作为getaddrinfo函数的hints参数中的ai_flags成员的值,以指示getaddrinfo函数不进行主机名解析,而直接使用传入的IP地址。这样可以避免主机名解析带来的延迟和不确定性,提高套接字的创建效率和可靠性。

hostname:主机名或IP地址字符串(IPv4的点分十进制/IPv6的16进制数串),如果为NULL,则表示本地主机
service:服务名称或端口号字符串,如果为NULL,则返回所有可用的套接字地址结构
hints:用于指定期望的套接字类型、协议及其他选项的addrinfo结构体指针,也可以为空指针
result:用于存储结果的addrinfo结构体指针
成功返回0,出错为非0

freeaddrinfo

释放由getaddrinfo返回的addrinfo结构

void freeaddrinfo(struct addrinfo *ai);

ai应指向第一个addrinfo结构

gai_strerror

由getaddrinfo返回的非0错误值的名字和含义gai_strerror作为它的参数返回一个指向信心串的指针

const char *gai_strerror(int error);

getnameinfo

它是getaddrinfo的互补函数,它以一个套接字地址结构为参数,返回其中的主机的一个字符串和描述其中服务的另一个字符串

int getnamefo(const struct sockaddr *sockaddr, socklen_t addrlen, char *host, socklen_t hostlen,char *serv, socklen_t servlen, int flags); 

成功返回0,出错为非0

host_serv

该函数初始化一个hints结构,可被getaddrinfo调用

struct addrinfo *host_serv(const char *hostname , const char *service , int family , int socktype);

成功返回指向addrinfo结构的指针,出错为NULL

getifaddrs

函数用于获取本机所有网络接口的信息。

#include <sys/types.h>
#include <ifaddrs.h>/*  getifaddrs创建一个链表,链表上的每个节点都是一个struct ifaddrs结构,getifaddrs()返回链表第一个元素的指针。
 *  成功返回0, 失败返回-1,同时errno会被赋允相应错误码。 */
int getifaddrs(struct ifaddrs **ifap);/*  释放ifaddrs */
void freeifaddrs(struct ifaddrs *ifa);struct ifaddrs {
   struct ifaddrs  *ifa_next;    /* 指向链表中下一个struct ifaddr结构 */
   char            *ifa_name;    /* 网络接口名 */
   unsigned int     ifa_flags;   /* 网络接口标志 */
   struct sockaddr *ifa_addr;    /* 指向一个包含网络地址的sockaddr结构 */
   struct sockaddr *ifa_netmask; /* 指向一个包含网络掩码的结构 */
   union {
       struct sockaddr *ifu_broadaddr;
                        /* 如果(ifa_flags&IFF_BROADCAST)有效,ifu_broadaddr指向一个包含广播地址的结构 */
       struct sockaddr *ifu_dstaddr;
                        /* 如果(ifa_flags&IFF_POINTOPOINT)有效,ifu_dstaddr指向一个包含p2p目的地址的结构 */
} ifa_ifu;
#define              ifa_broadaddr ifa_ifu.ifu_broadaddr
#define              ifa_dstaddr   ifa_ifu.ifu_dstaddr
   void            *ifa_data;    /* 指向一个缓冲区,其中包含地址族私有数据。没有私有数据则为NULL */
};

inet_pton

用于将点分十进制形式的IPv4地址或冒号十六进制表示的IPv6地址转换为二进制网络字节顺序的形式

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

af:地址家族(address family),可以是 AF_INET(对于IPv4)或 AF_INET6(对于IPv6)。
src:指向包含要转换的IP地址字符串的指针。
dst:指向足够大的缓冲区的指针,用于存储转换后的网络字节顺序格式的IP地址。对于IPv4,通常是一个struct in_addr;对于IPv6,则是一个struct in6_addr。
return: 如果转换成功,返回非零值


  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值