Linux网络编程—Day8

socket基础API终于学完了,好多哦,今天来学习网络信息API。

网络信息API

socket地址的两个要素,即IP地址和端口号,都是用数值表示的。 这不便于记忆,也不便于扩展(比如从IPv4转移到IPv6)。因此我们可以用主机名来访问一台机器,而避免直接使用其IP地址。 同样,我们用服务名称来代替端口号。比如,下面两条telnet命令具有完全相同的作用:

 

上面的例子中,telnet客户端程序是通过调用某些网络信息API来实现主机名到IP地址的转换,以及服务名称到端口号的转换的。

重要的网络信息API

  • gethostbyname和gethostbyaddr

gethostbyname函数根据主机名称获取主机的完整信息, gethostbyaddr函数根据IP地址获取主机的完整信息。函数定义如下:

#include<netdb.h>
struct hostent* gethostbyname(const char*name);
struct hostent* gethostbyaddr(const void*addr,size_t len,int type);

name参数指定目标主机的主机名,addr参数指定目标主机的IP地 址,len参数指定addr所指IP地址的长度,type参数指定addr所指IP地址 的类型,其合法取值包括AF_INET(用于IPv4地址)和AF_INET6(用 于IPv6地址)。这两个函数返回的都是hostent结构体类型的指针,hostent结构体的定义如下:

#include<netdb.h>
struct hostent
{
    char*h_name;/*主机名*/
    char**h_aliases;/*主机别名列表,可能有多个*/
    int h_addrtype;/*地址类型(地址族)*/
    int h_length;/*地址长度*/
    char**h_addr_list/*按网络字节序列出的主机IP地址列表*/
};
  • getservbyname和getservbyport

getservbyname函数根据名称获取某个服务的完整信息, getservbyport函数根据端口号获取某个服务的完整信息。这两个函数的定义如下:

#include<netdb.h>
struct servent* getservbyname(const char*name,const char*proto);
struct servent* getservbyport(int port,const char*proto);

name参数指定目标服务的名字,port参数指定目标服务对应的端口 号。proto参数指定服务类型,给它传递“tcp”表示获取流服务,给它传递“udp”表示获取数据报服务,给它传递NULL则表示获取所有类型的服务。这两个函数返回的都是servent结构体类型的指针,结构体servent的定义如下:

#include<netdb.h>
struct servent
{
    char*s_name;/*服务名称*/
    char**s_aliases;/*服务的别名列表,可能有多个*/
    int s_port;/*端口号*/
    char*s_proto;/*服务类型,通常是tcp或者udp*/
};

示例:通过主机名和服务名来访问目标服务器上的daytime服务,以获取该机器的系统时间:

注意,通过主机名访问服务器是要提前在/etc/hosts文件配置主机名:

客户端执行程序获取服务器的系统时间

 源代码如下:

#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <assert.h>

int main( int argc, char *argv[] )
{
	assert( argc == 2 );
	//获取主机名
	char *host = argv[1];
	//根据主机名获取主机的完整信息,存入hostinfo
	struct hostent* hostinfo = gethostbyname( host );
	assert( hostinfo );
	//根据名称获取某个服务的完整信息,存入servinfo
	struct servent* servinfo = getservbyname( "daytime", "tcp" );
	assert( servinfo );
	//输出该服务对应的端口号
	printf( "daytime port is %d\n", ntohs( servinfo->s_port ) );

	//注意下面代码,因为h_addr_list本身是使用网络字节序的地址列表,所以使用其
	//中的IP地址时,无须对目标IP地址转换字节序
	struct sockaddr_in address;
	address.sin_family = AF_INET;
	address.sin_port = servinfo->s_port;
	address.sin_addr = *( struct in_addr* )*hostinfo->h_addr_list;

	//创建一个socket套接字
	int sockfd = socket( AF_INET, SOCK_STREAM, 0 );
	//连接服务器
	int result = connect( sockfd, (struct sockaddr* )&address, sizeof( address ) );
	assert( result != -1 );

	//存储服务器发送的内容
	char buffer[128];
	//从缓冲区读取内容
	result = read( sockfd, buffer, sizeof( buffer ) );
	assert( result > 0 );
	buffer[ result ] = '\0';
	//打印服务器发送的内容
	printf( "the day tiem is: %s", buffer );
	close( sockfd );
    return 0;
}
  • getaddrinfo

getaddrinfo函数既能通过主机名获得IP地址(内部使用的是gethostbyname函数),也能通过服务名获得端口号(内部使用的是getservbyname函数),该函数的定义如下:

#include<netdb.h> 
int getaddrinfo(const char* hostname,const char* service,const struct addrinfo* hints,struct addrinfo** result);

hostname参数可以接收主机名,也可以接收字符串表示的IP地址,同样, service参数可以接收服务名,也可以接收字符串表示的十进制端口号,hints参数是应用程序给getaddrinfo的一个提示,以对getaddrinfo的输出进行更精确的控制。hints参数可以被设置为NULL,表示允许getaddrinfo反馈任何可用的结果。result参数指向一个链表,该链表用于存储getaddrinfo反馈的结果。getaddrinfo反馈的每一条结果都是addrinfo结构体类型的对象,结构体addrinfo的定义如下:

struct addrinfo
{
    int ai_flags;/*见后文*/
    int ai_family;/*地址族*/
    int ai_socktype;/*服务类型,SOCK_STREAM或SOCK_DGRAM*/
    int ai_protocol;/*见后文*/
    socklen_t ai_addrlen;/*socket地址ai_addr的长度*/
    char*ai_canonname;/*主机的别名*/
    struct sockaddr*ai_addr;/*指向socket地址*/
    struct addrinfo*ai_next;/*指向下一个sockinfo结构的对象*/
};

ai_protocol成员是指具体的网络协议,其含义和socket 系统调用的第三个参数相同,它通常被设置为0;

当我们使用hints参数的时候,可以设置其ai_flags,ai_family,ai_socktype和ai_protocol四个字段,其他字段则必须被设置为NULL。

  • getnameinfo

getnameinfo函数能通过socket地址同时获得以字符串表示的主机名(内部使用的是gethostbyaddr函数)和服务名(内部使用的是getservbyport函数)。

#include<netdb.h>
int getnameinfo(const struct sockaddr*sockaddr,socklen_t addrlen,char*host,socklen_t hostlen,char*serv,socklen_t servlen,int flags);

getnameinfo将返回的主机名存储在host参数指向的缓存中,将服务名存储在serv参数指向的缓存中,hostlen和servlen参数分别指定这两块缓存的长度。flags参数控制getnameinfo的行为,他可接收的选项如下:

 getaddrinfo和getnameinfo函数成功时返回0,失败则返回错误码,可能的错误码如下:

Linux下gai_strerror函数能将数值错误码errno转换成易读的字符串形式:

#include<netdb.h>
const char*gai_strerror(int error);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值