UNP卷1:第十一章(名字与地址转换)

1. gethostbyname函数

#include <netdb.h>

struct hostent *gethostbyname( const char *hostname );
               返回:若成功则为非空指针,若出错则为NULL且设置h_errno
而hostent的结构如下:

struct hostent{
    char    *h_name;
    char    *h_aliases;
    int        h_addrtype;
    int        h_length;
    char    **h_addr_list;
};
书上的例子如下:(实际上在ubuntu系统上,gethostbyname似乎会出错)

#include "myunp.h"

int main( int argc, char **argv )
{
	char	*ptr, **pptr;
	char	str[ INET_ADDRSTRLEN ];
	struct	hostent	*hptr;
	
	while ( --argc > 0 ){
		ptr = *++argv;
		if ( ( hptr = gethostbyname( ptr ) ) == NULL ){
			printf("gethostbyname error for host:%s:%s\n", ptr, hstrerror( h_errno ) );
			continue;
		}
		printf("official hostname:%s\n", hptr->h_name );
		for ( pptr = hptr->h_aliases; *pptr != NULL; pptr++ )
			printf("\talias:%s\n", *pptr );
		switch( hptr->h_addrtype ){
			case AF_INET:
				pptr = hptr->h_addr_list;	
			for ( ; *pptr != NULL; pptr++ )
					printf("\taddress name:%s\n", *pptr );
//					printf("\taddress:%s\n", inet_ntop( hptr->h_addrtype, *pptr, str, sizeof(str)));
			break;
			default:
				printf("unknown address type");
				break;
		}
	}

	exit(0);
}

程序输出:

root@ThinkPad-T430i:/home/leichaojian# cc hostent.c -o hostent
root@ThinkPad-T430i:/home/leichaojian# ./hostent www.baidu.com
official hostname:www.a.shifen.com
	alias:www.baidu.com
	address name:�a!kwww.�a!lifen.com
	address name:�a!lifen.com

    所以执行inet_ntop时候程序直接报异常。


2. 测试inet_ntop和inet_pton函数

#include "myunp.h"
  2 
  3 int main( void )
  4 {
  5     char *ptr = "127.0.0.1";
  6     char str[ 1024 ];
  7     struct sockaddr_in  servaddr;
  8 
  9     bzero( &servaddr, sizeof( servaddr ) );
 10     servaddr.sin_family = AF_INET;
 11     servaddr.sin_port = htons( SERV_PORT );
 12     inet_pton( AF_INET, ptr, &servaddr.sin_addr);
 13 
 14     inet_ntop( AF_INET, ( SA * )&servaddr.sin_addr, str, sizeof( str ) );
 15 
 16     printf("%s\n", str );
 17     return 0;
 18 }
程序输出:

leichaojian@ThinkPad-T430i:~$ ./test
127.0.0.1

 3. getservbyname和getservbyport函数

    一个根据给定名字查找相应服务,一个给定端口号和可选协议查找相应服务。

#include <stdio.h>
#include <netdb.h>

int main( int argc, char **argv )
{
	struct servent	*sptr;

	sptr = getservbyname( "domain", "udp" );
	sptr = getservbyname( "ftp", "tcp" );
	sptr = getservbyname( "ftp", "NULL" );
	sptr = getservbyname( "ftp", "udp" );
	
	sptr = getservbyport( htons( 53 ), "udp" );
	sptr = getservbyport( htons( 21 ), "tcp" );
	sptr = getservbyport( htons( 21 ), "NULL" );
	sptr = getservbyport( htons( 21 ), "udp" );

	return 0;
}


程序输出:

(gdb) break 8
Breakpoint 1 at 0x4005dc: file getservbynameport.c, line 8.
(gdb) r
Starting program: /home/leichaojian/getservbynameport 

Breakpoint 1, main (argc=1, argv=0x7fffffffde58) at getservbynameport.c:8
8		sptr = getservbyname( "domain", "udp" );
(gdb) n
9		sptr = getservbyname( "ftp", "tcp" );
(gdb) p *sptr
$1 = {s_name = 0x602010 "domain", s_aliases = 0x602020, s_port = 13568, s_proto = 0x60201b "udp"}
(gdb) n
10		sptr = getservbyname( "ftp", "NULL" );
(gdb) p *sptr
$2 = {s_name = 0x602010 "ftp", s_aliases = 0x602020, s_port = 5376, s_proto = 0x602018 "tcp"}
(gdb) n
11		sptr = getservbyname( "ftp", "udp" );
(gdb) p *sptr
Cannot access memory at address 0x0
(gdb) n
13		sptr = getservbyport( htons( 53 ), "udp" );
(gdb) p *sptr
Cannot access memory at address 0x0
(gdb) n
14		sptr = getservbyport( htons( 21 ), "tcp" );
(gdb) p *sptr
$3 = {s_name = 0x603290 "domain", s_aliases = 0x6032a0, s_port = 13568, s_proto = 0x60329b "udp"}
(gdb) n
15		sptr = getservbyport( htons( 21 ), "NULL" );
(gdb) p *sptr
$4 = {s_name = 0x603290 "ftp", s_aliases = 0x6032a0, s_port = 5376, s_proto = 0x603298 "tcp"}
(gdb) n
16		sptr = getservbyport( htons( 21 ), "udp" );
(gdb) p *sptr
Cannot access memory at address 0x0
(gdb) n
18		return 0;

4. getaddrinfo函数

    此函数可用来代替gethostbyname和gethostbyaddr。

#include <netdb.h>

int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );
           返回:若成功则为0,若出错则为非0
参数1为主机名或地址串(点分十进制数串),service参数是一个服务名或十进制端口号数串,hints目前就直接置为NULL,而result则是我们需要的信息:

struct addrinfo{
	int	ai_flags;
	int	ai_family;
	int	ai_socktype;
	int	ai_addrlen;
	socklen_t	ai_addrlen;
	char	*ai_canonname;
	struct sockaddr *ai_addr;
	struct addrinfo *ai_next;
};

测试用例如下:

#include <stdio.h>
#include <netdb.h>

int main( int argc, char **argv )
{
	struct addrinfo hints, *res;
	struct sockaddr_in	*addr;
	char	str[ 1024 ];
	getaddrinfo( "ThinkPad-T430i", "domain", NULL, &res );
	for ( ;res->ai_next;res = res->ai_next ){
		printf("ai_falgs:%d\n", res->ai_flags);
		printf("ai_family:%d\n", res->ai_family);
		printf("ai_socktype:%d\n", res->ai_socktype);
		printf("ai_addrlen:%d\n", res->ai_addrlen);
		printf("ai_canonname:%s\n", res->ai_canonname);

		addr = ( struct sockaddr_in * )res->ai_addr;
		printf("sin_family:%d\n", addr->sin_family);
		printf("sin_port:%d\n", ntohs( addr->sin_port ) );
		inet_ntop( addr->sin_family, &addr->sin_addr, str, sizeof( str ) );
		printf("sin_addr:%s\n", str);
	}

	return 0;
}
程序输出:

leichaojian@ThinkPad-T430i:~$ cc getaddrinfo.c
leichaojian@ThinkPad-T430i:~$ ./a.out
ai_falgs:40
ai_family:2
ai_socktype:1
ai_addrlen:16
ai_canonname:(null)
sin_family:2
sin_port:53
sin_addr:127.0.1.1

5. 使用getaddrinfo来完成TCP时间获取服务器程序

1)时间获取客户程序

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#define MAXLINE 1024

int tcp_connect( const char *host, const char *serv );

int main( int argc, char **argv )
{
	int		sockfd, n;
	char	recvline[ MAXLINE + 1 ];
	socklen_t	len;
	struct sockaddr_in	cliaddr;

	if ( argc != 3 ){
		printf("argument should be 3\n");
		exit(1);
	}
	sockfd = tcp_connect( argv[1], argv[2]);

	len = sizeof( cliaddr );
	getpeername( sockfd, ( struct sockaddr * )&cliaddr, len );
	inet_ntop( AF_INET, &cliaddr.sin_addr, recvline, sizeof( recvline ) );
	printf("connect to %s\n", recvline);

	while ( ( n = read( sockfd, recvline, MAXLINE )) > 0 ){
		recvline[ n ] = 0;
		fputs( recvline, stdout );
	}

	exit( 0 );
}
int tcp_connect( const char *host, const char *serv )
{
	int		sockfd, n;
	struct	addrinfo hints, *res, *ressave;
	struct	sockaddr_in	*cliaddr;

	bzero( &hints, sizeof( struct addrinfo ) );
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	if ( ( n = getaddrinfo( host, serv, &hints, &res ) ) != 0 ){
		printf("tcp_connect error for %s,%s:%s", host, serv, gai_strerror(n));
		exit(1);
	}

	ressave = res;
	do{
		sockfd = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
		if ( sockfd < 0 )
			continue;
		if ( connect( sockfd, res->ai_addr, res->ai_addrlen ) == 0 )
			break;
		//用于调试
		cliaddr = ( struct sockaddr_in * )res->ai_addr;
		close( sockfd );
	} while ( ( res = res->ai_next ) != NULL );

	if ( res == NULL )
		printf("tcp_connect error for %s,%s\n", host, serv );

	freeaddrinfo( ressave );

	return ( sockfd );
}

程序输出:

leichaojian@ThinkPad-T430i:~$ ./newdaytimetcpcli ThinkPad-T430i daytime
connect to 0.0.0.0
30 SEP 2014 00:21:58 CST
 备注:这里要开启时间,具体操作如下

1) 安装

leichaojian@ThinkPad-T430i:~$ sudo apt-get install xinetd
2) 修改配置如下:

leichaojian@ThinkPad-T430i:~$ cd /etc/xinetd.d
leichaojian@ThinkPad-T430i:/etc/xinetd.d$ vim daytime
3) 具体修改:

将disable=yes改为disable=no(两处均要修改)

4)我不知道如何重新载入,所以直接重启了电脑。


2)时间获取服务器程序

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <time.h>
#define MAXLINE 1024

int tcp_listen( const char *host, const char *serv, socklen_t *addrlenp );

int main( int argc, char **argv )
{
	int		listenfd, connfd;
	socklen_t	len;
	char	buff[ MAXLINE ];
	time_t	ticks;
	struct	sockaddr_in	cliaddr;
	
	listenfd = tcp_listen( argv[ 1 ], argv[ 2 ], NULL );

	for ( ; ; ){
		len = sizeof( cliaddr );
		connfd = accept( listenfd, ( struct sockaddr *)&cliaddr, &len );
		inet_ntop( AF_INET, &cliaddr.sin_addr, buff, sizeof( buff ) );
		printf("conneciton from %s\n", buff );

		ticks = time( NULL );
		snprintf( buff, sizeof( buff ), "%.24s\r\n", ctime(&ticks));
		write( connfd, buff, strlen(buff));

		close( connfd );
	}
}
int tcp_listen( const char *host, const char *serv, socklen_t *addrlenp )
{
	int		listenfd, n;
	const	int on = 1;
	struct	addrinfo hints, *res, *ressave;

	bzero( &hints, sizeof( struct addrinfo ) );
	hints.ai_flags = AI_PASSIVE;
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	if ( ( n = getaddrinfo( host, serv, &hints, &res ) ) != 0 ){
		printf("tcp_listen error for %s,%s: %s\n", host, serv, gai_strerror(n));
	}
	ressave = res;

	do{
		listenfd = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
		if ( listenfd < 0 )
			continue;
		setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
		if ( bind( listenfd, res->ai_addr, res->ai_addrlen) == 0 )
			break;
		close( listenfd );
	} while(( res = res->ai_next) != NULL );

	if ( res == NULL ){
		printf("tcp_listen error for %s,%s", host, serv);
	}
	listen( listenfd, 5 );

	if ( addrlenp )
		*addrlenp = res->ai_addrlen;
	freeaddrinfo(ressave);

	return (listenfd );
}

服务端运行:

leichaojian@ThinkPad-T430i:~$ ./newdaytimetcpserv ThinkPad-T430i 9877
conneciton from 127.0.0.1

客户端运行:

leichaojian@ThinkPad-T430i:~$ ./newdaytimetcpcli ThinkPad-T430i 9877
connect to 0.0.0.0
Tue Sep 30 18:14:25 2014

6. 使用getaddrinfo来完成UDP时间获取服务器程序

1)时间获取客户端程序

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>

#define MAXLINE 1024

int udp_client(const char *host, const char *serv, struct sockaddr **saptr, socklen_t *lenp );

int main(int argc, char **argv)
{
	int		sockfd, n;
	char	recvline[ MAXLINE + 1 ];
	socklen_t	salen;
	struct	sockaddr *sa;

	if (argc != 3){
		printf("argument should be 3\n");
		exit(1);
	}
	sockfd = udp_client(argv[1], argv[2], (void **)&sa, &salen);

	sendto(sockfd, "", 1, 0, sa, salen);
	n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
	recvline[n] = '\0';
	fputs(recvline, stdout);

	exit(0);
}
int udp_client(const char *host, const char *serv, struct sockaddr **saptr, socklen_t *lenp )
{
	int		sockfd, n;
	struct	addrinfo hints, *res, *ressave;

	bzero(&hints, sizeof(struct addrinfo));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_DGRAM;

	if ((n = getaddrinfo(host, serv, &hints, &res)) != 0){
		printf("udp_client error for %s,%s:%s\n", host, serv, gai_strerror(n));
		exit(1);
	}
	ressave = res;
	do{
		sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
		if (sockfd >= 0)
			break;
	}while ((res = res->ai_next) != NULL);

	if (res == NULL){
		printf("udp_client error for %s,%s\n", host, serv);
		exit(1);
	}

	*saptr = malloc(res->ai_addrlen);
	memcpy(*saptr, res->ai_addr, res->ai_addrlen);
	*lenp = res->ai_addrlen;

	freeaddrinfo(ressave);

	return (sockfd);
}

程序输出:

leichaojian@ThinkPad-T430i:~$ ./newdaytimeudpcli ThinkPad-T430i daytime
30 SEP 2014 18:37:24 CST

2) 时间获取服务端程序

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <time.h>

#define MAXLINE 1024

int udp_server(const char *host, const char *serv, socklen_t *addrlenp);

int main(int argc, char **argv)
{
	int		sockfd;
	ssize_t	n;
	char	buff[MAXLINE];
	time_t	ticks;
	socklen_t	len;
	struct	sockaddr_in	cliaddr;

	sockfd = udp_server( argv[1], argv[2], NULL);
	for ( ; ; ){
		len = sizeof(cliaddr);
		n = recvfrom(sockfd, buff, MAXLINE, 0, (struct sockaddr *)&cliaddr, &len);
		inet_ntop(AF_INET, &cliaddr.sin_addr, buff, sizeof(buff));
		printf("datagram from %s\n", buff );

		ticks = time(NULL);
		snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
		sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&cliaddr, len);
	}
}
int udp_server(const char *host, const char *serv, socklen_t *addrlenp)
{
	int		sockfd, n;
	struct	addrinfo hints, *res, *ressave;

	bzero(&hints, sizeof(struct addrinfo));
	hints.ai_flags = AI_PASSIVE;
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_DGRAM;

	if ((n = getaddrinfo(host, serv, &hints, &res)) != 0){
		printf("udp_server error for %s,%s:%s", host, serv, gai_strerror(n));
		exit(1);
	}
	ressave = res;

	do{
		sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
		if (sockfd < 0)
			continue;
		if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0)
			break;
		close(sockfd);
	}while ((res = res->ai_next) != NULL);

	if (res == NULL){
		printf("udp_server error for %s,%s\n", host, serv);
		exit(1);
	}

	if (addrlenp)
		*addrlenp = res->ai_addrlen;
	freeaddrinfo(ressave);

	return (sockfd);
}

服务器运行:

leichaojian@ThinkPad-T430i:~$ ./newdaytimeudpserv ThinkPad-T430i 9877
datagram from 127.0.0.1

客户端运行:

leichaojian@ThinkPad-T430i:~$ ./newdaytimeudpcli ThinkPad-T430i 9877
Tue Sep 30 18:56:41 2014

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值