HTTP服务器的简单实现 墨蓝 2022-09-22 03:46 156阅读 0赞 在 [HTTP学习笔记——报文格式][HTTP] 一文中,我们已经可以了解到HTTP的报文格式,有了报文格式,我们就可以实现简单的HTTP服务器了。 一个简单的HTTP服务器会包含一下几个部分: \+ 接收HTTP请求 \+ 解析HTTP请求 \+ 构造HTTP响应 \+ 发送HTTP响应。 我们看一下如何用C语言实现简单的HTTP服务器。 在下面代码中会用到几个自定义的重要的结构体,这里先列出来: typedef struct request_startup{ char method[64]; char req_url[1024]; char version[64]; } RequestS; typedef struct URL{ char file_path[64]; char query_string[512]; } URL; 我们先看一下main函数 int main(int argc, char** argv) { int sockfd, clientfd; short port; struct sockaddr_in serv_addr, client_addr; socklen_t serv_len, client_len; port = htons(PORT); sockfd = Socket(AF_INET, SOCK_STREAM, 0); memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = port; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // inet_pton(AF_INET, SERV_ADDR, &serv_addr.sin_addr); Bind(sockfd, (struct sockaddr*)&serv_addr, sizeof (serv_addr)); Listen(sockfd, 6); while (1) { client_len = sizeof (client_addr); clientfd = Accept(sockfd, (struct sockaddr*)&client_addr, &client_len); handle_request(clientfd); close(clientfd); } close(sockfd); return 0; } ### 接收请求 ### 首先我们要单间一个socket套接字的服务端程序,然后阻塞在`Accept`等待HTTP客户端的请求。当接收到客户端的连接时,我们定义了函数`handle_request(clientfd);`来处理客户端的请求。在`handle_request()`函数中,我们根据HTTP请求报文的格式,解析HTTP报文 ### 解析HTTP报文: ### int handle_request(int clientfd) { char buf[1024]; char method[32]; char req_url[1024]; char version[32]; int i, j; int numchars; printf("Handle_request\n"); numchars = get_line(clientfd, buf, sizeof(buf)); // Get start line printf("get line: %s\n", buf); i = 0; j = 0; /* get method from start_line */ while ( !isspace(buf[j]) && i < (sizeof (method) - 1)) { method[i] = buf[j]; ++i; ++j; } method[i] = '\0'; /* Get Request URL from start_line */ i = 0; while( isspace(buf[j]) ) ++j; while ( !isspace(buf[j]) && i < (sizeof (req_url) -1 )) { req_url[i] = buf[j]; ++i; ++j; } req_url[i] = '\0'; printf("Get URL:%s\n", req_url); /* Get Version from start_line */ i = 0; while( isspace(buf[j]) ) ++j; while ( buf[j] != '\0' && i < (sizeof (version) -1 )) { version[i] = buf[j]; ++i; ++j; } version[i] = '\0'; if(!strcasecmp(method, "GET")) { printf("%s\n", req_url); response_GET(clientfd, req_url); printf("GET finished%s\n", req_url); } else { NotSupportMethod(); } return 0; } 首先通过`get_line()`读取HTTP报文的起始行,然后解析出HTTP请求报文的方法、请求的URL。 目前我们只支持**GET**方法,其他方法进入`NotSupportMethod()`处理。 当HTTP报文请求的方法是GET时,我们进入`response_GET()`处理。 void response_GET(int clientfd, char *url_str) { printf("Response GET...\n"); URL url; prase_url(url_str, &url); serve_file(clientfd, url.file_path); } 该函数有两个调用,`prase_url()` 用来解析客户端请求的url, 然后将他转换为服务器上响应资源的地址。 比如客户端的输入的网址为`http://127.0.0.1:8080/index.html`,则报文中的URL为`/index.html` 该报文请求的是服务器上相对路径为`./index.html`的资源。 解析了URL之后,我们就需要想客户端做出响应了。对于`GET`请求而言,就是把报文请求的资源返回给客户端,这一部分通过`serve_file`实现。 ### 构造并发送HTTP响应 ### void serve_file(int clientfd, const char* file_path) { printf("Serve file...\n"); FILE *resource; char buf[1024]; char filename[1024]; int numchars = 1; int file_len = 0; filename[0] = '.'; filename[1] = '\0'; strcat(filename, file_path); printf("respond file: %s\n", filename); resource = fopen(filename, "r"); fseek(resource,0,2); //指针:移动到文件尾部 file_len = ftell(resource); //返回指针偏离文件头的位置(即文件中字符个数) fseek(resource,0,0); //指针:移动到文件尾部 printf("====file_len:%d=======\n", file_len); if (resource == NULL) { printf("File not found!\n"); //not_found(client); } else { response_header(clientfd, filename); fgets(buf, sizeof(buf), resource); while (!feof(resource)) { send(clientfd, buf, strlen(buf), 0); fgets(buf, sizeof(buf), resource); } } fclose(resource); } HTTP响应报文我们主要分为两部分: 非实体部分(包括起始行和首部)、实体部分(资源的内容)。 对于一个简单的`GET`请求,其实体部分就是资源`./index.html`的内容。 实体部分(资源的内容)的构造与发送其实就是读取资源内容,然后发送给客户端: fgets(buf, sizeof(buf), resource); while (!feof(resource)) { send(clientfd, buf, strlen(buf), 0); fgets(buf, sizeof(buf), resource); } 非实体部分(起始行和首部)的构造与发送在函数`response_header(clientfd, filename);`中实现。 void response_header(int client, const char* filename) { char buf[1024]; (void)filename; /* could use filename to determine file type */ ssize_t n; strcpy(buf, "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: 125\r\n\r\n"); send(client, buf, strlen(buf), 0); } 这里要提一下`Content-Length: 125`这一个首部,这里我写了固定值125(其实它是资源内容的大小,这里为了简单说明,在代码中写了固定值)。`Content-Length`这个首部可以说是必须的,它能帮助客户端识别HTTP响应报文的结束。正常情况下,我们必须给这个首部赋上**准确的值**,否则一些客户端可能无法正确的识别HTTP报文,发生连接错误、浏览器不进行缓存。(如会发现浏览器已经请求到了index.html页面,但是闪一下就不见了。)。 [HTTP]: http://blog.csdn.net/windeal3203/article/details/51730296%20%E3%80%8AHTTP%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E2%80%94%E2%80%94%E6%8A%A5%E6%96%87%E6%A0%BC%E5%BC%8F%E3%80%8B
相关 使用Java实现简单的HTTP服务器 在Java中,我们可以使用内置的`HttpServer`类来创建一个简单的HTTP服务器。以下是一个基本的例子: ```java import java.io.IOExcep ╰半橙微兮°/ 2024年09月11日 03:21/ 0 赞/ 10 阅读
相关 Netty 实现简单的HTTP服务器 1 概述 HTTP 是基于请求/响应模式的:客户端向服务器发送一个 HTTP 请求,然后服务器将会返回一个 HTTP 响应。Netty 提供了多种编码器和解码器以简化对这 痛定思痛。/ 2022年11月16日 13:59/ 0 赞/ 182 阅读
相关 HTTP服务器的简单实现 在 [HTTP学习笔记——报文格式][HTTP] 一文中,我们已经可以了解到HTTP的报文格式,有了报文格式,我们就可以实现简单的HTTP服务器了。 一个简单的HTTP服 墨蓝/ 2022年09月22日 03:46/ 0 赞/ 157 阅读
相关 HTTP:Web服务器的实现 不管是什么Web服务器,它们都能够接收请求资源的HTTP请求,将其内容回送给客户端 Web服务器实现了HTTP和相关的TCP连接处理。负责管理Web服务器提供的资源,以 深藏阁楼爱情的钟/ 2022年08月30日 14:56/ 0 赞/ 168 阅读
相关 Python 实现一个简单的http服务器 背景 原文链接:http://blog.csdn.net/ordeder/article/details/22490373 写一个python脚本,实现简单的http服 深碍√TFBOYSˉ_/ 2022年08月03日 15:46/ 0 赞/ 180 阅读
相关 C#实现一个最简单的HTTP服务器 [C\实现一个最简单的HTTP服务器][C_HTTP] 2014-08-21 分类:[.NET开发][.NET]、[编程开发][Link 1]、[首页精华][Lin 川长思鸟来/ 2022年07月16日 01:20/ 0 赞/ 182 阅读
相关 java基于Socket实现的一个简单的HTTP服务器 package com.zg.kyrie; import java.io.BufferedReader; import java.io.IOE 落日映苍穹つ/ 2022年05月17日 12:54/ 0 赞/ 148 阅读
相关 如何用Netty实现一个简单HTTP服务器 本文代码基于netty 4.1版本。 既然你搜到这篇文章了,说明对netty有所了解了,不废话直接上例子,基本上根据netty官网DEMO修改而成。 HttpServer 绝地灬酷狼/ 2022年03月26日 06:20/ 0 赞/ 247 阅读
相关 php socket实现简单的http服务器 <?php function onMessage($connection) { //拼装返回的html内容 $ 比眉伴天荒/ 2022年03月07日 01:43/ 0 赞/ 230 阅读
还没有评论,来说两句吧...