博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
HTTP1.1 基础: 用C语言实现200行内的极简http server
阅读量:4207 次
发布时间:2019-05-26

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

对HTTP1.1协议有基本的了解后,就可以用C语言来实现一个极简的http server了。HTTP1.1 协议基础可以看这篇文章 。

这里实现的极简 http server 主要完成此功能: 通过URL访问server根目录的html类型文件,server目录默认就是httpd可执行文件的所在目录。这个简单的demo的目的是为了加深对http交互的理解,代码如下:

#include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)#define LOG(fmt, ...) printf(fmt" %s:%d\n", ##__VA_ARGS__, __FILENAME__, __LINE__)#define EXIT(error) do {perror(error); exit(EXIT_FAILURE);} while(0)#define MAX_REQUEST_LEN 10240#define MAX_METHOD_LEN 32#define MAX_URI_LEN 256int parse_request(int sockfd, char *method, char *uri) { char buff[MAX_REQUEST_LEN] = { 0}; ssize_t len = recv(sockfd, buff, sizeof(buff), 0); if (len <= 0) { LOG("call recv error, ret %d", (int)len); return -1; } char *cur = buff; int i = 0; while (i < MAX_METHOD_LEN && !isspace(*cur)) { method[i++] = *cur++; } method[i] = '\0'; while(isspace(*cur)) cur++; i = 0; while (i < MAX_URI_LEN && !isspace(*cur)) { uri[i++] = *cur++; } uri[i] = '\0'; return 0;}void unimplemented(int client) { char buff[] = "HTTP/1.0 501 Method Not Implemented\r\n" "Content-Type: text/html\r\n" "\r\n" "Method Not Implemented"; send(client, buff, sizeof(buff), 0);}void not_found(int client){ char buff[] = "HTTP/1.0 404 NOT FOUND\r\n" "Content-Type: text/html\r\n" "\r\n" "The resource specified is unavailable.\r\n"; send(client, buff, strlen(buff), 0);}void url_decode(const char *src, char *dest) { const char *p = src; char code[3] = { 0}; while (*p && *p != '?') { if(*p == '%') { memcpy(code, ++p, 2); *dest++ = (char)strtoul(code, NULL, 16); p += 2; } else { *dest++ = *p++; } } *dest = '\0';}void do_get(int sockfd, const char *uri) { char filename[MAX_URI_LEN] = { 0}; const char *cur = uri + 1; size_t len = strlen(cur); if (len == 0) { strcpy(filename, "index.html"); } else { url_decode(cur, filename); } printf("%s\n", filename); FILE *f = fopen(filename, "r"); if (NULL == f) { not_found(sockfd); return; } char header[] = "HTTP/1.0 200 OK\r\n" "Content-Type: text/html\r\n" "\r\n"; send(sockfd, header, sizeof(header), 0); char line[128] = { 0}; while (fgets(line, sizeof(line), f) != NULL) { send(sockfd, line, strlen(line), 0); memset(line, 0, sizeof(line)); } char end[] = "\r\n"; send(sockfd, end, 2, 0); fclose(f);}void *process(void* psockfd) { int sockfd = *(int*)psockfd; char method[MAX_METHOD_LEN] = { 0}; char uri[MAX_URI_LEN] = { 0}; if (parse_request(sockfd, method, uri) != 0) goto FINAL; if (strcmp(method, "GET") == 0) { do_get(sockfd, uri); } else { unimplemented(sockfd); }FINAL: close(sockfd); return NULL;}int create_server_fd (unsigned int port) { int serverfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (serverfd == -1) EXIT("create socket fail"); struct sockaddr_in server; memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = INADDR_ANY; if (bind(serverfd,(struct sockaddr *)&server, sizeof(server)) == -1) EXIT("bind fail"); if (listen(serverfd, 10) == -1) EXIT("listen fail"); return serverfd;}int main() { int serverfd, connfd; pthread_t tid; struct sockaddr_in client; socklen_t clientlen = sizeof(client); unsigned int port = 5000; serverfd = create_server_fd(port); LOG("Server started, listen port %d", port); while (1) { connfd = accept(serverfd, (struct sockaddr *)&client, &clientlen); if (pthread_create(&tid, NULL, process, &connfd) == 0) { unsigned char *ip = (unsigned char*)&client.sin_addr.s_addr; unsigned short port = client.sin_port; LOG("request %u.%u.%u.%u:%5u", ip[0], ip[1], ip[2], ip[3], port); } else { EXIT("create thread fail"); } } return 0;}

这个http server demo采用的并发模型是多线程,编译的时候记得链接-lpthread

转载地址:http://tbqli.baihongyu.com/

你可能感兴趣的文章
【GoLang】Web工作方式
查看>>
Launch Sublime Text 3 from the command line
查看>>
【数据库之mysql】mysql的安装(一)
查看>>
【数据库之mysql】 mysql 入门教程(二)
查看>>
【HTML5/CSS/JS】A list of Font Awesome icons and their CSS content values(一)
查看>>
【HTML5/CSS/JS】<br>与<p>标签区别(二)
查看>>
【HTML5/CSS/JS】开发跨平台应用工具的选择(三)
查看>>
【心灵鸡汤】Give it five minutes不要让一个好主意随风而去
查看>>
【React Native】Invariant Violation: Application AwesomeProject has not been registered
查看>>
【ReactNative】真机上无法调试 could not connect to development server
查看>>
【XCode 4.6】常用快捷键 特别是格式化代码ctrl+i
查看>>
【iOS游戏开发】icon那点事 之 实际应用(二)
查看>>
【iOS游戏开发】icon那点事 之 图标设计(三)
查看>>
【IOS游戏开发】之测试发布(Distribution)
查看>>
【IOS游戏开发】之IPA破解原理
查看>>
【一天一道LeetCode】#45. Jump Game II
查看>>
【一天一道LeetCode】#46. Permutations
查看>>
【一天一道LeetCode】#47. Permutations II
查看>>
【一天一道LeetCode】#48. Rotate Image
查看>>
【一天一道LeetCode】#56. Merge Intervals
查看>>