C语言网络编程(3)— 通过DNS连接到百度
一、gethostbyname()函数
我们现在认知一台计算机主机通常采用直观可读的名字。例如百度我们会记住 www.baidu.com 而不是他的IP地址。对于大多数的应用程序来说应该是处理名字而不是处理地址。如果说对于一个点分十进制来说还好记住,那么当使用IPv6时,IP地址就不是那么好记了。
而Linux下的函数 gethostbyname是查找主机名最基本的函数。如果调用成功,它就返回一个指向hostent结构的指针,该结构中含有所查找主机的所有IPv4地址。
函数原型如下:
struct hostent *gethostbyname(const char *name);
调用成功返回hostent结构体的指针,hostent结构体如下
struct hostent {
char *h_name; /* 正式的主机名 */
char **h_aliases; /* 主机别名列表 */
int h_addrtype; /* 地址类型,AF_INET->IPv4, AF_INET6->IPv6 */
int h_length; /* 地址长度,单位为字节 */
char **h_addr_list; /* 地址对应的所有IP地址列表 */
}
注:一个地址有多个IP对应,比如一个大型网站可能南方,北方,国外等不同的地方都有主机,总之是很多情况,需要多个IP。
二、编程获取百度的IP地址
要使用gethostbyname()函数则需要导入头文件:
#include <netdb.h>
我们直接使用gethostbyname()获取百度域名的信息
// 1、使用gethostbyname()获取百度域名的信息
struct hostent *host_ptr = gethostbyname("www.baidu.com");
然后将消息打印出来
// 2、打印百度域名的信息
printf("official name:%s \n",host_ptr->h_name); // 正式的主机名
for(i=0; host_ptr->h_aliases[i] != NULL; i++) // 别名
printf("alias name :%s \n",host_ptr->h_aliases[i]);
// 地址类型,AF_INET->IPv4, AF_INET6->IPv6
printf("address type :%s \n",host_ptr->h_addrtype == AF_INET ?"IPv4":"IPv6");
for(i=0; host_ptr->h_addr_list[i] != NULL; i++) // IP地址列表
printf("addr %d :%s \n",i, inet_ntoa( *(struct in_addr*)host_ptr->h_addr_list[i]));
编译,运行结果如下:
然后我们在终端使用ping
命令,可以看到,我们同样得到了两个IP地址
三、连接百度服务器
尝试连接到百度服务器
// 3、使用socket()函数获取一个TCP客户端socket文件描述符
int tcp_client = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == tcp_client)
{
perror("socket");
return -1;
}
// 4、百度服务端的IP地址和端口,使用第一个ip地址,端口号80
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET; // 设置地址族为IPv4
server_addr.sin_port = htons(80); // 设置地址的端口号信息
server_addr.sin_addr.s_addr = *(in_addr_t*)host_ptr->h_addr_list[0]; // 设置IP地址
// 5、链接到服务器
ret = connect(tcp_client, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
perror("connect");
else
printf("connect result, ret = %d.\n", ret);
连接成功:
然后发送一个GET请求,
// 6. 发送GET请求
char sendbuf[]={"GET / HTTP/1.1\n\n"};
ret = send(tcp_client, sendbuf, strlen(sendbuf),0);
// 7、等待接收服务端发送过来的数据,最大接收1024个字节
char recvbuf[1024] = {0};
ret = recv(tcp_client, recvbuf, sizeof(recvbuf), 0);
// 8、将接收到的数据打印出来
printf("Recvdate: \n%s \n",recvbuf);
编译,运行,访问成功
四、代码
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
int main(void)
{
int ret,i=0;
// 1、使用gethostbyname()获取百度域名的信息
struct hostent *host_ptr = gethostbyname("www.baidu.com");
//struct hostent *host_ptr = gethostbyname("www.163.com");//http://www.hfut.edu.cn/
// 2、打印百度域名的信息
printf("official name:%s \n",host_ptr->h_name); // 正式的主机名
for(i=0; host_ptr->h_aliases[i] != NULL; i++) // 别名
printf("alias name :%s \n",host_ptr->h_aliases[i]);
// 地址类型,AF_INET->IPv4, AF_INET6->IPv6
printf("address type :%s \n",host_ptr->h_addrtype == AF_INET ?"IPv4":"IPv6");
for(i=0; host_ptr->h_addr_list[i] != NULL; i++) // IP地址列表
printf("addr %d :%s \n",i, inet_ntoa( *(struct in_addr*)host_ptr->h_addr_list[i]));
// 3、使用socket()函数获取一个TCP客户端socket文件描述符
int tcp_client = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == tcp_client)
{
perror("socket");
return -1;
}
// 4、百度服务端的IP地址和端口,使用第一个ip地址,端口号80
struct sockaddr_in server_addr = {0};
server_addr.sin_family = AF_INET; // 设置地址族为IPv4
server_addr.sin_port = htons(80); // 设置地址的端口号信息
server_addr.sin_addr.s_addr = *(in_addr_t*)host_ptr->h_addr_list[0]; // 设置IP地址
// 5、链接到服务器
ret = connect(tcp_client, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
perror("connect");
else
printf("connect success.\n");
// 6. 发送GET请求
char sendbuf[]={"GET / HTTP/1.1\n\n"};
ret = send(tcp_client, sendbuf, strlen(sendbuf),0);
// 7、等待接收服务端发送过来的数据,最大接收1024个字节
char recvbuf[1024] = {0};
ret = recv(tcp_client, recvbuf, sizeof(recvbuf), 0);
// 8、将接收到的数据打印出来
printf("Recvdate: \n%s \n",recvbuf);
// 9、关闭套接字
close(tcp_client);
}