Linux C/C++服务器
http服务器的实现
http服务器说的是在reactor网络io框架基础上加上http协议,实现可与浏览器交互的后端服务,reactor在之前有介绍,下面我们先来看看http协议都有哪些东西
http协议
http消息分两部分,一个是客户端请求消息,一个是服务器响应消息
http客户端请求消息
客户端发送一个http请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行(/r/n)和请求数据四部分组成
客户端请求示例:
GET /hello.txt HTTP/1.1 User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 Host: www.example.com Accept-Language: en, mi
http服务器响应消息
HTTP 响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文
服务端响应示例:
HTTP/1.1 200 OK Date: Mon, 27 Jul 2009 12:28:53 GMT Server: Apache Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT ETag: "34aa387-d-1568eb00" Accept-Ranges: bytes Content-Length: 51 Vary: Accept-Encoding Content-Type: text/plain
结果:网页端显示
Hello World! My payload includes a trailing CRLF.
关于http请求方法、响应头信息、状态码这些详细信息,在这个文档中都有
reactor服务端框架
框架主要由这四个接口组成,1.ntyreactor_run() 保证服务端7*24小时运行 2.accpet_cb() 与客户端建立连接 3.recv_cb() 接受客户端http请求 4.send_cb() 发送http响应
其中accept_cb()可以做ip限制、负载均衡的场景中使用
reactor框架
reactor框架在之前有介绍,这里对之前版本的reactor代码做了部分优化,让它看起来更漂亮更健壮一些;
event事件中新增回调函数及http方法
struct ntyevent { int fd; int events; void *arg; int (*callback)(int fd, int events, void *arg); int status; char buffer[BUFFER_LENGTH]; char wbuffer[BUFFER_LENGTH]; int length; int wlength; //long last_active; // http reqeust int method; char resource[RESOURCE_LENGTH]; };
event回调函数设置接口,在send_cb和recv_cb接口的最后调用它
void nty_event_set(struct ntyevent *ev, int fd, NCALLBACK callback, void *arg) { ev->fd = fd; ev->callback = callback; ev->events = 0; ev->arg = arg; //ev->last_active = time(NULL); return ; }
在epoll_wait事件触发后调用相应的回调函数
//ntyreactor_run while (1) { int nready = epoll_wait(reactor->epfd, events, MAX_EPOLL_EVENTS, 1000); if (nready < 0) { printf("epoll_wait error, exit\n"); continue; } for (i = 0;i < nready;i ++) { struct ntyevent *ev = (struct ntyevent*)events[i].data.ptr; if ((events[i].events & EPOLLIN) && (ev->events & EPOLLIN)) { ev->callback(ev->fd, events[i].events, ev->arg); //here } if ((events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)) { ev->callback(ev->fd, events[i].events, ev->arg); } } }
那么剩下的就只有http协议如何去解析recv_cb()和回传的问题send_cb()
recv_cb()
parse
// connection // sock_item --> fd, rbuffer, wbuffer, clientaddr int recv_cb(int fd, int events, void *arg) { struct ntyreactor *reactor = (struct ntyreactor*)arg; struct ntyevent *ev = ntyreactor_idx(reactor, fd); if (ev == NULL) return -1; int len = recv(fd, ev->buffer, BUFFER_LENGTH, 0); nty_event_del(reactor->epfd, ev); if (len > 0) { ev->length = len; ev->buffer[len] = '\0'; //printf("recv [%d]:%s\n", fd, ev->buffer); nty_http_request(ev); // parser http hdr nty_event_set(ev, fd, send_cb, reactor); nty_event_add(reactor->epfd, EPOLLOUT, ev); } else if (len == 0) { nty_event_del(reactor->epfd, ev); //printf("recv_cb --> disconnect\n"); close(ev->fd); } else { if (errno == EAGAIN && errno == EWOULDBLOCK) { // } else if (errno == ECONNRESET){ nty_event_del(reactor->epfd, ev); close(ev->fd); } //printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno)); } return len; }
send_cb()
responce
int send_cb(int fd, int events, void *arg) { struct ntyreactor *reactor = (struct ntyreactor*)arg; struct ntyevent *ev = ntyreactor_idx(reactor, fd); if (ev == NULL) return -1; nty_http_response(ev); //encode int len = send(fd, ev->wbuffer, ev->wlength, 0); if (len > 0) { //printf("resource: %s\n", ev->resource); int filefd = open(ev->resource, O_RDONLY); //if (filefd < 0) return -1; struct stat stat_buf; fstat(filefd, &stat_buf); int flag = fcntl(fd, F_GETFL, 0); flag &= ~O_NONBLOCK; fcntl(fd, F_SETFL, flag); int ret = sendfile(fd, filefd, NULL, stat_buf.st_size); if (ret == -1) { printf("sendfile: errno: %d\n", errno); } flag |= O_NONBLOCK; fcntl(fd, F_SETFL, flag); close(filefd); send(fd, "\r\n", 2, 0); nty_event_del(reactor->epfd, ev); nty_event_set(ev, fd, recv_cb, reactor); nty_event_add(reactor->epfd, EPOLLIN, ev); } else { nty_event_del(reactor->epfd, ev); close(ev->fd); //printf("send[fd=%d] error %s\n", fd, strerror(errno)); } return len; }
代码实现,比较简单,直接看源码就好
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本