博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
从零开始一个http服务器(三)-返回response 构造
阅读量:4515 次
发布时间:2019-06-08

本文共 6344 字,大约阅读时间需要 21 分钟。

从零开始一个http服务器(三)

代码地址 :

git checkout step3
运行:
gcc request.h request.c response.h response.c main.c tools/utils.c tools/utils.h && ./a.out
测试:
浏览器打开

response 构造

  • 观察response结构
  • 定义并返回response
  • 测试

观察response结构

上一节,我们成功解析了http的request,但是我们在浏览器访问我们的地址http://127.0.0.1:9734/ 还是无法正常显示。这是因为我们没有给浏览器返回它能读懂的信息。这一节我们的目标是让浏览器正确的显示信息。什么样的才是浏览器能读懂的信息呢?不妨我们用telnet来模拟向百度主页发一个http request,来看看百度主页返回的是什么信息。

伪造一个http request的字符串,注意 headers 中的 Host 代表我们要访问的主机地址。

GET / HTTP/1.1Host: www.baidu.comUser-Agent: curl/7.54.0Accept: */*Content-Type: application/x-www-form-urlencode

再用telnet连接www.baidu.com 并指定80端口(80为http默认端口,telnet默认端口为23), telnet www.baidu.com 80

复制黏贴上面我们构造的字符串回车后,你应该能看到如下类似的返回结果:

Trying 119.75.216.20...Connected to www.a.shifen.com.Escape character is '^]'.GET / HTTP/1.1Host: www.baidu.comUser-Agent: curl/7.54.0Accept: */*Content-Type: application/x-www-form-urlencodeHTTP/1.1 200 OKAccept-Ranges: bytesCache-Control: private, no-cache, no-store, proxy-revalidate, no-transformConnection: Keep-AliveContent-Length: 2381Content-Type: text/htmlDate: Sat, 18 Aug 2018 02:12:08 GMTEtag: "588604c8-94d"Last-Modified: Mon, 23 Jan 2017 13:27:36 GMTPragma: no-cacheServer: bfe/1.0.8.18Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/
...Connection closed by foreign host.

HTTP/1.1 200 OK开始就是百度放回给我们的结果。让人惊喜的是这种结构和request很类型,除了第一行外。仔细看看:

  • 第一行为 http版本号 response返回码 response返回结果描述
  • 第二行开始为headers
  • 空行后,接body

定义并返回response

根据response的结构有的信息定义我们的结构体.

/* response.h*/#include 
#include "tools/utils.h"#include "request.h"struct http_response { char * version; char * code; // 状态返回码 char * desc; // 返回描述 struct Map * headers; char * body; };void initHttpResponse(struct http_response * response);void doResponse( struct http_request * request, FILE * stream);void outputToFile( struct http_response * response, FILE * stream);

构造我们的response数据, 我们每次都返回相同的数据.

/* response.c*/#include 
/* fprintf NULL */#include
/* strlen */#include "response.h"#include "request.h"#include "tools/utils.h"void initHttpResponse(struct http_response * response) { response->version = NULL; response->code = NULL; response->desc = NULL; response->headers = NULL; response->body = NULL;}void doResponse(struct http_request * request, FILE * stream) { struct http_response responseInstance; struct http_response * response = &responseInstance; initHttpResponse(response); response->version = "HTTP/1.1"; response->code = "200"; response->desc = "OK"; char * content = "hello everyone"; char content_len[25]; sprintf(content_len, "%lu", strlen(content)); struct Item * item = newItem( "Content-Length", content_len ); struct Map map_instance; initMap(&map_instance); response->headers = &map_instance; mapPush(response->headers, item); response->body = content; outputToFile(response, stream); // clean releaseMap(request->headers);}void outputToFile(struct http_response * response, FILE * stream) { // output version code desc int r = fprintf(stream, "%s %s %s \r\n", response->version, response->code, response->desc ); // output headers struct Map* map = response->headers; struct List* list; struct Item* item; int print_item_cnt = 0; for(int i=0; i
table_len; i++) { list = map->table[i]; if(list == NULL) { continue; } item = list->start; while(item != NULL) { fprintf(stream, "%s: %s\r\n", item->key, item->value ); item = item->next; } } // output body if(response->body != NULL) { fprintf(stream, "\r\n%s", response->body); }}

写一个测试用例,将本应向客服端发送的数据输出到stdout

/* test/responseTest.ctest cmd:gcc  ../request.h ../request.c ../response.h ../response.c ../tools/utils.h ../tools/utils.c  responseTest.c && ./a.out*/#include 
#include "../request.h" #include "../response.h" int main() { struct http_request request; char data[] = "POST / HTTP/1.1\r\nContent-Length: 3\r\n\r\n111"; struct Map headers; request.headers = &headers; parse_request(&request, data); doResponse(&request, stdout);}

cd 到 test 目录

运行: gcc ../request.h ../request.c ../response.h ../response.c ../tools/utils.h ../tools/utils.c responseTest.c && ./a.out
可以看到正确的输出:

---------------------------method is: POSTurl is: /http version is: HTTP/1.1the headers are :{'Content-Length': ' 3'}body is 111---------------------------HTTP/1.1 200 OKContent-Length: 27hello everyone

现在修改main函数,加上我们的reponse处理逻辑

/**run cmd:gcc request.h request.c response.h response.c main.c tools/utils.c tools/utils.h && ./a.out*/#include 
#include
#include
#include
#include
#include
#include
#include
#include "request.h"#include "response.h"#define MAXREQUESTLEN 50000void initString(char * c, int length) { int i = 0; while(i < length) { *(c + i) = '\0'; i++; }}int main() { int server_sockfd, client_sockfd; socklen_t server_len, client_len; struct sockaddr_in server_address; struct sockaddr_in client_address; server_sockfd = socket(AF_INET, SOCK_STREAM, 0); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = inet_addr("127.0.0.1"); server_address.sin_port = htons(9734); server_len = sizeof(server_address); bind(server_sockfd, (struct sockaddr *)&server_address, server_len); listen(server_sockfd, 5); while(1) { char ch[MAXREQUESTLEN]; initString(ch, MAXREQUESTLEN); // char send_str[] = "hello world !\n"; client_len = sizeof(client_address); client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len); read(client_sockfd, &ch, MAXREQUESTLEN); printf("%s\n", ch); struct http_request request; struct Map headers; request.headers = &headers; parse_request(&request, ch); FILE* fp = fdopen(client_sockfd, "w+"); doResponse(&request, fp); fflush(fp); fclose(fp); // write(client_sockfd, &send_str, sizeof(send_str)/sizeof(send_str[0])); }}

测试

启动我们的server gcc request.h request.c response.h response.c main.c tools/utils.c tools/utils.h && ./a.out

再在浏览器访问我们的服务器地址
现在浏览器能识别我们的返回结果了!

转载于:https://www.cnblogs.com/chens-smile/p/9498340.html

你可能感兴趣的文章
在路上,三线城市互联网创业记录
查看>>
spark 编译遇到的错误及解决办法(五)
查看>>
框架篇: React + React-Router + antd + nodejs + express框架开发运用(nodejs做前后端server)...
查看>>
8、使用转换流处理标准输入
查看>>
Git 常用命令
查看>>
Why does Http header contains "X-SourceFiles"?
查看>>
uva 10976 fractions again(水题)——yhx
查看>>
爬虫实战篇---数据入库之去重与数据库
查看>>
CMPSC-132 – Programming and Computation
查看>>
洛谷 P4878 [USACO05DEC] 布局
查看>>
Python MySQL Django一些问题
查看>>
OpenGL------显示列表
查看>>
『科学计算』高斯判别分析模型实现
查看>>
『Pickle』数据结构持久化模块_常用方法记录
查看>>
pycharm 的包路径设置export PYTHONPATH=$PYTHONPATH
查看>>
SQL语句创建函数
查看>>
查找数组元素位置
查看>>
vue开发的打包配置
查看>>
jquery基础
查看>>
端口作用
查看>>