1)web_server.c
#include <stdio.h> #include <string.h> #include <stdlib.h> #include "uv.h" #include "../3rd/http_parser/http_parser.h" typedef void(*web_get_handle)(uv_stream_t* stream, char* url); typedef void(*web_post_handle)(uv_stream_t* stream, char* url, char* body); struct url_node { char* url; web_get_handle get; web_post_handle post; }; static struct url_node* alloc_url_node(char* url, web_get_handle get, web_post_handle post) { struct url_node* node = malloc(sizeof(struct url_node)); memset(node, 0, sizeof(struct url_node)); node->url = strdup(url); node->get = get; node->post = post; return node; } static struct url_node* url_node[1024]; static int url_count = 0; static void register_web_handle(char* url, web_get_handle get, web_post_handle post) { url_node[url_count] = alloc_url_node(url, get, post); url_count++; } static struct url_node* get_url_node(char* url, int len) { for (int i = 0; i < url_count; i++) { if (strncmp(url, url_node[i]->url, len) == 0) { return url_node[i]; } } return NULL; } static uv_loop_t* loop = NULL; static uv_tcp_t l_server; static void uv_alloc_buf(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) { if (handle->data != NULL) { free(handle->data); handle->data = NULL; } buf->base = malloc(suggested_size + 1); buf->len = suggested_size; handle->data = buf->base; } static void on_close(uv_handle_t* handle) { printf("client close!\n"); if (handle->data) { free(handle->data); handle->data = NULL; } } static void on_shutdown(uv_shutdown_t* req, int status) { uv_close((uv_handle_t*)req->handle, on_close); free(req); } static void after_write(uv_write_t* req, int status) { if (status == 0) { printf("write success!\n"); } uv_buf_t* w_buf = req->data; if (w_buf) { free(w_buf); } free(req); } static void send_data(uv_stream_t* stream, unsigned char* send_data, int send_len) { uv_write_t* w_req = malloc(sizeof(uv_write_t)); uv_buf_t* w_buf = malloc(sizeof(uv_buf_t)); unsigned char* send_buf = malloc(send_len); memcpy(send_buf, send_data, send_len); w_buf->base = send_buf; w_buf->len = send_len; w_req->data = w_buf; uv_write(w_req, stream, w_buf, 1, after_write); } static char req_url[4096]; int on_url(http_parser* p, const char* at, size_t length) { strncpy(req_url, at, length); req_url[length] = 0; return 0; } static int filter_url(char* url) { char* walk = url; int len = 0; while (url != '?' && *url != '\0') { len++; url++; } return len; } static void on_http_request(uv_stream_t* stream, char* req, int len) { http_parser_settings settings; http_parser_settings_init(&settings); settings.on_url = on_url; http_parser p; http_parser_init(&p, HTTP_REQUEST); http_parser_execute(&p, &settings, req, len); int url_len = filter_url(req_url); struct url_node* node = get_url_node(req_url, url_len); printf("%s\n", req_url); if (node == NULL) { return; } switch (p.method) { case HTTP_GET: if (node->get != NULL) { node->get(stream, req_url); } break; case HTTP_POST: if (node->post != NULL) { } break; default: break; } } static void test_get(uv_stream_t* stream, char* url) { printf("%s\n", url); char* body = "SUCCESS TEST1"; static char respons_buf[4096]; char* walk = respons_buf; sprintf(walk, "HTTP/1.1 %d %s\r\n", 200, "OK"); walk += strlen(walk); sprintf(walk, "transfer-encoding:%s\r\n", "identity"); walk += strlen(walk); sprintf(walk, "content-length: %d\r\n\r\n", strlen(body)); walk += strlen(walk); sprintf(walk, "%s", body); send_data(stream, respons_buf, strlen(respons_buf)); } static void test2_get(uv_stream_t* stream, char* url) { printf("%s\n", url); char* body = "SUCCESS TEST2"; static char respons_buf[4096]; char* walk = respons_buf; sprintf(walk, "HTTP/1.1 %d %s\r\n", 200, "OK"); walk += strlen(walk); sprintf(walk, "transfer-encoding:%s\r\n", "identity"); walk += strlen(walk); sprintf(walk, "content-length: %d\r\n\r\n", strlen(body)); walk += strlen(walk); sprintf(walk, "%s", body); send_data(stream, respons_buf, strlen(respons_buf)); } static void after_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { if (nread < 0) { uv_shutdown_t* reg = malloc(sizeof(uv_shutdown_t)); memset(reg, 0, sizeof(uv_shutdown_t)); uv_shutdown(reg, stream, on_shutdown); return; } buf->base[nread] = 0; printf("recv %d\n", nread); printf("%s\n", buf->base); // 处理http请求 on_http_request(stream, buf->base, buf->len); } static void uv_connection(uv_stream_t* server, int status) { printf("new client come in\n"); uv_tcp_t* client = malloc(sizeof(uv_tcp_t)); memset(client, 0, sizeof(uv_tcp_t)); uv_tcp_init(loop, client); uv_accept(server, (uv_stream_t*)client); //让event loop管理读 uv_read_start((uv_stream_t*)client, uv_alloc_buf, after_read); } int main(int argc, char** argv) { register_web_handle("/test", test_get, NULL); register_web_handle("/test2", test2_get, NULL); int ret; loop = uv_default_loop(); uv_tcp_init(loop, &l_server); // 配置我想要eventloop帮我管理的类型 struct sockaddr_in addr; uv_ip4_addr("0.0.0.0", 6080, &addr); ret = uv_tcp_bind(&l_server, (const struct sockaddr*)&addr, 0); if (ret != 0) { goto failed; } uv_listen((uv_stream_t*)&l_server, SOMAXCONN, uv_connection); uv_run(loop, UV_RUN_DEFAULT); failed: printf("end\n"); system("pause"); return 0; }效果
可见,不管是什么语言,只要在tcp协议的基础上,根据http的需求,发送给请求端指定的报文,那么就升级成指定的协议了。
总结webserver做5件事情: