【网络编程开发】16.域名解析与http服务器实现原理

16.域名解析与http服务器实现原理

gethostbyname 函数

  1. 原型

    #include <netdb.h>
    struct hostent *gethostbyname(const char *hostname);
    
  2. 功能:获取主机名对应的IP地址

  3. 参数hostname:要查询的主机名。

  4. 返回值

    • 成功时,返回一个指向hostent结构的指针。
    • 失败时,返回NULL。
  5. 注意:使用完该函数后记得使用endhostent函数进行销毁,清理缓冲区。

  6. struct hostent

    • struct hostent {
          char  *h_name;  /* 官方域名 */
          char **h_aliases;  /* 别名*/
          int    h_addrtype;  /* 地址族(地址类型) */
          int    h_length;  /* 地址长度 */
      char **h_addr_list;  /* 地址列表 */
      }
      #define h_addr h_addr_list[0] /* 实现向后兼容性 */
      
    • h_name :主机的正式名称

    • h_aliases:主机的备用名称数组,以 NULL 结尾指针

    • h_addrtype:地址类型;(AF_INETAF_INET6

    • h_length:地址的长度(以字节为单位)

    • h_addr_list:指向主机网络地址的指针数组(按网络字节顺序),由 NULL 指针终止

    • h_addr h_addr_list:中的第一个地址,以实现向后兼容性

  7. 示例

    #include <stdio.h>
    #include <netdb.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <arpa/inet.h>
    
    int main(int argc, char *argv[])
    {
    	int i;
    /*检查参数*/
    	if(argc < 2){
    		printf("%s <host name>\n", argv[0]);
    		exit(0);
    	}
    /*将域名赋值给结构体*/
    	struct hostent *host = gethostbyname(argv[1]);
    
    /*打印结构体的内容*/
    	for(i = 0; host->h_aliases[i] != NULL; i++){
    		printf("%s\n", host->h_aliases[i]);
    	}
    	printf("Address type:%s\n",
    			host->h_addrtype == AF_INET ? "AF_INET":"AF_INET6");
    
    	for(i = 0; host->h_addr_list[i] != NULL; i++){
    		printf("IP address %d:%s\n", i, inet_ntoa(*(struct in_addr *)host->h_addr_list[i]));
    	}
    	endhostent();//关闭主机信息文件
    	return 0;
    }
    

    运行程序:./test www.baidu.com

    在这里插入图片描述

HTTP的操作过程

在这里插入图片描述

  1. DNS解析:当用户在浏览器中输入URL或点击链接时,浏览器首先需要将域名转换为对应的IP地址。这一过程称为DNS解析。浏览器会向DNS服务器查询该域名对应的IP地址。
  2. 建立TCP连接:获取到IP地址后,浏览器会与服务器建立TCP连接,这一过程涉及到TCP协议的三次握手。这是为了确保数据能够准确、有序地在网络中传输。
  3. 封装HTTP请求数据包:一旦TCP连接建立成功,浏览器会封装一个HTTP请求数据包,其中包含了请求行、请求头和请求体等信息。
  4. 发送HTTP请求:随后,浏览器通过已经建立的TCP连接,向服务器发送HTTP请求。这个请求可能包含对网页文档的请求,或是对图片、CSS、JavaScript等资源的请求。
  5. 服务器处理请求:服务器接收到HTTP请求后,会根据请求的内容进行处理。这包括读取请求的资源、执行相应的脚本等操作。
  6. 服务器返回响应:处理完请求后,服务器会返回一个HTTP响应,其中包括了状态码、响应头和响应体等信息。状态码告诉客户端请求是否成功,或者遇到了何种错误。
  7. 浏览器解析HTML:收到响应后,浏览器开始解析HTML代码,并构建DOM树。同时,浏览器会根据HTML中的标签和属性,请求必要的资源文件,如CSS样式表、JavaScript脚本以及图片等。
  8. 浏览器渲染页面:在取得并解析所有资源文件后,浏览器开始渲染页面。这个过程包括计算每个元素的位置和样式,最终将页面呈现出来。
  9. 关闭TCP连接:一旦服务器发送了请求的数据,通常会主动关闭TCP连接。但在某些情况下,如果响应头信息中包含Connection:keep-alive,则连接仍然保持打开状态,以便后续在同一连接上发送更多请求

实现http

home.html

<html>
<head>
<title>server name</title>
<meta charset="utf-8">
</head>
<body>
<body>
<h1>文档标题</h1>
<p>Hello World!</p>
</body>
</body>
</html>

http-head.txt

HTTP/1.1 200 OK
Content-Type: text/html
Connection: close

server.c

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <strings.h>

#define PORT 80
#define BACKLOG 5
#define HTTPFILE "http-head.txt"
#define HTMLFILE "home.html"

int ClientHandle(int newfd);

int main(int argc, char *argv[])
{
	int fd, newfd;
	struct sockaddr_in addr;
	/*创建套接字*/
	fd = socket(AF_INET, SOCK_STREAM, 0);
	if(fd < 0){
		perror("socket");
		exit(0);
	}
	int opt = 1;
	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &opt, sizeof(opt) ))
		perror("setsockopt");

	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = 0;
	/*绑定通信结构体*/
	if(bind(fd, (struct sockaddr *)&addr, sizeof(addr) ) == -1){
		perror("bind");
		exit(0);
	}
	/*设置套接字为监听模式*/
	if(listen(fd, BACKLOG) == -1){
		perror("listen");
		exit(0);
	}
	/*接受客户端的连接请求,生成新的用于和客户端通信的套接字*/
	newfd = accept(fd, NULL, NULL);
	if(newfd < 0){
		perror("accept");
		exit(0);
	}
	ClientHandle(newfd);
	close(fd);
	return 0;
}

int ClientHandle(int newfd){
	int file_fd = -1;
	char buf[BUFSIZ] = {};
	int ret;
/*接收数据*/
	do {
		ret = recv(newfd, buf, BUFSIZ, 0);
	}while(ret < 0 && errno == EINTR);//如果接收到的数据个数小于0,或者错误为非阻塞时未收到数据的标志EINTR
	if(ret < 0){
		perror("recv");
		exit(0);
	}else if(ret == 0){//客户端主动结束
		close(newfd);
		return 0;
	}else{
		printf("=====================================\n");
		printf("%s", buf);
		fflush(stdout);//刷新缓冲区
	}

/*读取文件HTTPFILE的内容并发送*/
	bzero(buf, ret);
	file_fd = open(HTTPFILE, O_RDONLY);
	if(file_fd < 0){
		perror("open");
		exit(0);
	}
	ret = read(file_fd, buf, BUFSIZ);
	printf("%s\n", buf);
	send(newfd, buf, ret, 0);
	close(file_fd);

/*读取文件HTMLFILE的内容并发送*/
	bzero(buf, ret);
	file_fd = open(HTMLFILE, O_RDONLY);
	if(file_fd < 0){
		perror("open");
		exit(0);
	}
	ret = read(file_fd, buf, BUFSIZ);
	printf("%s\n", buf);
	send(newfd, buf, ret, 0);
	close(file_fd);

	close(newfd);
	return 0;
}
  1. 查看ip地址 ifconfig
    在这里插入图片描述

  2. 运行程序 sudo ./server

  3. 打开浏览器输入ip地址

在这里插入图片描述

最近更新

  1. TCP协议是安全的吗?

    2024-06-15 19:14:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-15 19:14:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-15 19:14:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-15 19:14:03       18 阅读

热门阅读

  1. 运维监控系统

    2024-06-15 19:14:03       7 阅读
  2. ArrayList<Integer>()转为int[]的几种方式

    2024-06-15 19:14:03       7 阅读
  3. c++_0基础_讲解5 判断语句

    2024-06-15 19:14:03       8 阅读
  4. 算法训练营day23补签

    2024-06-15 19:14:03       6 阅读
  5. ISO七层模型 tcp/ip

    2024-06-15 19:14:03       8 阅读
  6. 2022C语言二级真题

    2024-06-15 19:14:03       9 阅读
  7. TCP协议参数设置&说明

    2024-06-15 19:14:03       5 阅读
  8. 探索机器学习:深入理解Sklearn基础

    2024-06-15 19:14:03       8 阅读