网络地址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的长度。
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应该为NULL。
5)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: 如果转换成功,返回非零值
标签:sockaddr,函数,int,编程,char,地址,指针,struct From: https://www.cnblogs.com/radixun/p/18015245