• http/https服务器实现


    需要解决的问题:

    1.http与reactor的关系

    2.GET

    3.POST

    4.cgi

    accept_cb:建立TCP连接

    recv_cb: 接受客户端http请求

    send_cb:发送http响应

    执行是有先后顺序,tcp连接的生命周期:

    1.accept_cb

    2.recv_cb

    3.send_cb

    http_request

    接收次数比发送的次数少,叫做粘包。

    解决办法:1.使用分隔符 \r\n\r\n 2.定义包的长度

    http_response由两部分头和body

    1. int filefd = open(ev->resource, O_RDONLY);
    2. struct stat stat_buf;
    3. fstat(filefd, &stat_buf);
    4. close(filefd);

    一般发送磁盘数据时,需要将磁盘数据读取到内存中,再发送出去。使用sendfile,原理是使用mmap,内存映射,将文件地址映射到内存中,再调用send,节省空间,零拷贝。拷贝是由cpu使用。sendfile不需要cpu参与,因为是零拷贝。

    区别路径还是文件:S_ISDIR(stat_buf.st_mode) S_ISREG(stat_buf.st_mode)

    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <sys/socket.h>
    5. #include <sys/epoll.h>
    6. #include <arpa/inet.h>
    7. #include <fcntl.h>
    8. #include <unistd.h>
    9. #include <errno.h>
    10. #include <time.h>
    11. #include <sys/stat.h>
    12. #include <sys/sendfile.h>
    13. #define BUFFER_LENGTH 4096
    14. #define MAX_EPOLL_EVENTS 1024
    15. #define SERVER_PORT 8888
    16. #define PORT_COUNT 1
    17. #define HTTP_WEBSERVER_HTML_ROOT "html"
    18. #define HTTP_METHOD_GET 0
    19. #define HTTP_METHOD_POST 1
    20. typedef int NCALLBACK(int ,int, void*);
    21. struct ntyevent {
    22. int fd;
    23. int events;
    24. void *arg;
    25. int (*callback)(int fd, int events, void *arg);
    26. int status;
    27. char buffer[BUFFER_LENGTH];
    28. int length;
    29. long last_active;
    30. // http param
    31. int method; //
    32. char resource[BUFFER_LENGTH];
    33. int ret_code;
    34. };
    35. struct eventblock {
    36. struct eventblock *next;
    37. struct ntyevent *events;
    38. };
    39. struct ntyreactor {
    40. int epfd;
    41. int blkcnt;
    42. struct eventblock *evblk; //fd --> 100w
    43. };
    44. int recv_cb(int fd, int events, void *arg);
    45. int send_cb(int fd, int events, void *arg);
    46. struct ntyevent *ntyreactor_idx(struct ntyreactor *reactor, int sockfd);
    47. void nty_event_set(struct ntyevent *ev, int fd, NCALLBACK callback, void *arg) {
    48. ev->fd = fd;
    49. ev->callback = callback;
    50. ev->events = 0;
    51. ev->arg = arg;
    52. ev->last_active = time(NULL);
    53. return ;
    54. }
    55. int nty_event_add(int epfd, int events, struct ntyevent *ev) {
    56. struct epoll_event ep_ev = {0, {0}};
    57. ep_ev.data.ptr = ev;
    58. ep_ev.events = ev->events = events;
    59. int op;
    60. if (ev->status == 1) {
    61. op = EPOLL_CTL_MOD;
    62. } else {
    63. op = EPOLL_CTL_ADD;
    64. ev->status = 1;
    65. }
    66. if (epoll_ctl(epfd, op, ev->fd, &ep_ev) < 0) {
    67. printf("event add failed [fd=%d], events[%d]\n", ev->fd, events);
    68. return -1;
    69. }
    70. return 0;
    71. }
    72. int nty_event_del(int epfd, struct ntyevent *ev) {
    73. struct epoll_event ep_ev = {0, {0}};
    74. if (ev->status != 1) {
    75. return -1;
    76. }
    77. ep_ev.data.ptr = ev;
    78. ev->status = 0;
    79. epoll_ctl(epfd, EPOLL_CTL_DEL, ev->fd, &ep_ev);
    80. return 0;
    81. }
    82. int readline(char *allbuf, int idx, char *linebuf) {
    83. int len = strlen(allbuf);
    84. for(;idx < len;idx ++) {
    85. if (allbuf[idx] == '\r' && allbuf[idx+1] == '\n') {
    86. return idx+2;
    87. } else {
    88. *(linebuf++) = allbuf[idx];
    89. }
    90. }
    91. return -1;
    92. }
    93. int http_request(struct ntyevent *ev) {
    94. // GET, POST
    95. char linebuf[1024] = {0};
    96. int idx = readline(ev->buffer, 0, linebuf);
    97. if (strstr(linebuf, "GET")) {
    98. ev->method = HTTP_METHOD_GET;
    99. //uri
    100. int i = 0;
    101. while (linebuf[sizeof("GET ") + i] != ' ') i++;
    102. linebuf[sizeof("GET ")+i] = '\0';
    103. sprintf(ev->resource, "./%s/%s", HTTP_WEBSERVER_HTML_ROOT, linebuf+sizeof("GET "));
    104. } else if (strstr(linebuf, "POST")) {
    105. }
    106. }
    107. int recv_cb(int fd, int events, void *arg) {
    108. struct ntyreactor *reactor = (struct ntyreactor*)arg;
    109. struct ntyevent *ev = ntyreactor_idx(reactor, fd);
    110. int len = recv(fd, ev->buffer, BUFFER_LENGTH, 0); //
    111. if (len > 0) {
    112. ev->length = len;
    113. ev->buffer[len] = '\0';
    114. printf("C[%d]:%s\n", fd, ev->buffer); //http
    115. http_request(ev);
    116. //send();
    117. nty_event_del(reactor->epfd, ev);
    118. nty_event_set(ev, fd, send_cb, reactor);
    119. nty_event_add(reactor->epfd, EPOLLOUT, ev);
    120. } else if (len == 0) {
    121. nty_event_del(reactor->epfd, ev);
    122. close(ev->fd);
    123. //printf("[fd=%d] pos[%ld], closed\n", fd, ev-reactor->events);
    124. } else {
    125. nty_event_del(reactor->epfd, ev);
    126. close(ev->fd);
    127. printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
    128. }
    129. return len;
    130. }
    131. int http_response(struct ntyevent *ev) {
    132. if (ev == NULL) return -1;
    133. memset(ev->buffer, 0, BUFFER_LENGTH);
    134. #if 0
    135. const char *html = "hello http

      King

      \r\n\r\n"
      ;
    136. ev->length = sprintf(ev->buffer,
    137. "HTTP/1.1 200 OK\r\n\
    138. Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n\
    139. Content-Type: text/html;charset=ISO-8859-1\r\n\
    140. Content-Length: 83\r\n\r\n%s",
    141. html);
    142. #else
    143. printf("resource: %s\n", ev->resource);
    144. int filefd = open(ev->resource, O_RDONLY);
    145. if (filefd == -1) { // return 404
    146. ev->ret_code = 404;
    147. ev->length = sprintf(ev->buffer,
    148. "HTTP/1.1 404 Not Found\r\n"
    149. "Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n"
    150. "Content-Type: text/html;charset=ISO-8859-1\r\n"
    151. "Content-Length: 85\r\n\r\n"
    152. "404 Not Found

      404

      \r\n\r\n"
      );
    153. } else {
    154. struct stat stat_buf;
    155. fstat(filefd, &stat_buf);
    156. close(filefd);
    157. if (S_ISDIR(stat_buf.st_mode)) {
    158. ev->ret_code = 404;
    159. ev->length = sprintf(ev->buffer,
    160. "HTTP/1.1 404 Not Found\r\n"
    161. "Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n"
    162. "Content-Type: text/html;charset=ISO-8859-1\r\n"
    163. "Content-Length: 85\r\n\r\n"
    164. "404 Not Found

      404

      \r\n\r\n"
      );
    165. } else if (S_ISREG(stat_buf.st_mode)) {
    166. ev->ret_code = 200;
    167. ev->length = sprintf(ev->buffer,
    168. "HTTP/1.1 200 OK\r\n"
    169. "Date: Thu, 11 Nov 2021 12:28:52 GMT\r\n"
    170. "Content-Type: text/html;charset=ISO-8859-1\r\n"
    171. "Content-Length: %ld\r\n\r\n",
    172. stat_buf.st_size );
    173. }
    174. }
    175. #endif
    176. return ev->length;
    177. }
    178. int send_cb(int fd, int events, void *arg) {
    179. struct ntyreactor *reactor = (struct ntyreactor*)arg;
    180. struct ntyevent *ev = ntyreactor_idx(reactor, fd);
    181. http_response(ev);
    182. //
    183. int len = send(fd, ev->buffer, ev->length, 0);
    184. if (len > 0) {
    185. printf("send[fd=%d], [%d]%s\n", fd, len, ev->buffer);
    186. if (ev->ret_code == 200) {
    187. int filefd = open(ev->resource, O_RDONLY);
    188. struct stat stat_buf;
    189. fstat(filefd, &stat_buf);
    190. sendfile(fd, filefd, NULL, stat_buf.st_size);
    191. close(filefd);
    192. }
    193. nty_event_del(reactor->epfd, ev);
    194. nty_event_set(ev, fd, recv_cb, reactor);
    195. nty_event_add(reactor->epfd, EPOLLIN, ev);
    196. } else {
    197. nty_event_del(reactor->epfd, ev);
    198. close(ev->fd);
    199. printf("send[fd=%d] error %s\n", fd, strerror(errno));
    200. }
    201. return len;
    202. }
    203. int accept_cb(int fd, int events, void *arg) {
    204. struct ntyreactor *reactor = (struct ntyreactor*)arg;
    205. if (reactor == NULL) return -1;
    206. struct sockaddr_in client_addr;
    207. socklen_t len = sizeof(client_addr);
    208. int clientfd;
    209. if ((clientfd = accept(fd, (struct sockaddr*)&client_addr, &len)) == -1) {
    210. if (errno != EAGAIN && errno != EINTR) {
    211. }
    212. printf("accept: %s\n", strerror(errno));
    213. return -1;
    214. }
    215. int flag = 0;
    216. if ((flag = fcntl(clientfd, F_SETFL, O_NONBLOCK)) < 0) {
    217. printf("%s: fcntl nonblocking failed, %d\n", __func__, MAX_EPOLL_EVENTS);
    218. return -1;
    219. }
    220. struct ntyevent *event = ntyreactor_idx(reactor, clientfd);
    221. nty_event_set(event, clientfd, recv_cb, reactor);
    222. nty_event_add(reactor->epfd, EPOLLIN, event);
    223. printf("new connect [%s:%d], pos[%d]\n",
    224. inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), clientfd);
    225. return 0;
    226. }
    227. int init_sock(short port) {
    228. int fd = socket(AF_INET, SOCK_STREAM, 0);
    229. fcntl(fd, F_SETFL, O_NONBLOCK);
    230. struct sockaddr_in server_addr;
    231. memset(&server_addr, 0, sizeof(server_addr));
    232. server_addr.sin_family = AF_INET;
    233. server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    234. server_addr.sin_port = htons(port);
    235. bind(fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
    236. if (listen(fd, 20) < 0) {
    237. printf("listen failed : %s\n", strerror(errno));
    238. }
    239. return fd;
    240. }
    241. int ntyreactor_alloc(struct ntyreactor *reactor) {
    242. if (reactor == NULL) return -1;
    243. if (reactor->evblk == NULL) return -1;
    244. struct eventblock *blk = reactor->evblk;
    245. while (blk->next != NULL) {
    246. blk = blk->next;
    247. }
    248. struct ntyevent *evs = (struct ntyevent*)malloc((MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));
    249. if (evs == NULL) {
    250. printf("ntyreactor_alloc ntyevents failed\n");
    251. return -2;
    252. }
    253. memset(evs, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));
    254. struct eventblock *block = (struct eventblock *)malloc(sizeof(struct eventblock));
    255. if (block == NULL) {
    256. printf("ntyreactor_alloc eventblock failed\n");
    257. return -2;
    258. }
    259. memset(block, 0, sizeof(struct eventblock));
    260. block->events = evs;
    261. block->next = NULL;
    262. blk->next = block;
    263. reactor->blkcnt ++; //
    264. return 0;
    265. }
    266. struct ntyevent *ntyreactor_idx(struct ntyreactor *reactor, int sockfd) {
    267. int blkidx = sockfd / MAX_EPOLL_EVENTS;
    268. while (blkidx >= reactor->blkcnt) {
    269. ntyreactor_alloc(reactor);
    270. }
    271. int i = 0;
    272. struct eventblock *blk = reactor->evblk;
    273. while(i ++ < blkidx && blk != NULL) {
    274. blk = blk->next;
    275. }
    276. return &blk->events[sockfd % MAX_EPOLL_EVENTS];
    277. }
    278. int ntyreactor_init(struct ntyreactor *reactor) {
    279. if (reactor == NULL) return -1;
    280. memset(reactor, 0, sizeof(struct ntyreactor));
    281. reactor->epfd = epoll_create(1);
    282. if (reactor->epfd <= 0) {
    283. printf("create epfd in %s err %s\n", __func__, strerror(errno));
    284. return -2;
    285. }
    286. struct ntyevent *evs = (struct ntyevent*)malloc((MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));
    287. if (evs == NULL) {
    288. printf("ntyreactor_alloc ntyevents failed\n");
    289. return -2;
    290. }
    291. memset(evs, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));
    292. struct eventblock *block = (struct eventblock *)malloc(sizeof(struct eventblock));
    293. if (block == NULL) {
    294. printf("ntyreactor_alloc eventblock failed\n");
    295. return -2;
    296. }
    297. memset(block, 0, sizeof(struct eventblock));
    298. block->events = evs;
    299. block->next = NULL;
    300. reactor->evblk = block;
    301. reactor->blkcnt = 1;
    302. return 0;
    303. }
    304. int ntyreactor_destory(struct ntyreactor *reactor) {
    305. close(reactor->epfd);
    306. //free(reactor->events);
    307. struct eventblock *blk = reactor->evblk;
    308. struct eventblock *blk_next = NULL;
    309. while (blk != NULL) {
    310. blk_next = blk->next;
    311. free(blk->events);
    312. free(blk);
    313. blk = blk_next;
    314. }
    315. return 0;
    316. }
    317. int ntyreactor_addlistener(struct ntyreactor *reactor, int sockfd, NCALLBACK *acceptor) {
    318. if (reactor == NULL) return -1;
    319. if (reactor->evblk == NULL) return -1;
    320. //reactor->evblk->events[sockfd];
    321. struct ntyevent *event = ntyreactor_idx(reactor, sockfd);
    322. nty_event_set(event, sockfd, acceptor, reactor);
    323. nty_event_add(reactor->epfd, EPOLLIN, event);
    324. return 0;
    325. }
    326. int ntyreactor_run(struct ntyreactor *reactor) {
    327. if (reactor == NULL) return -1;
    328. if (reactor->epfd < 0) return -1;
    329. if (reactor->evblk == NULL) return -1;
    330. struct epoll_event events[MAX_EPOLL_EVENTS+1];
    331. int checkpos = 0, i;
    332. while (1) {
    333. /*
    334. long now = time(NULL);
    335. for (i = 0;i < 100;i ++, checkpos ++) {
    336. if (checkpos == MAX_EPOLL_EVENTS) {
    337. checkpos = 0;
    338. }
    339. if (reactor->events[checkpos].status != 1) {
    340. continue;
    341. }
    342. long duration = now - reactor->events[checkpos].last_active;
    343. if (duration >= 60) {
    344. close(reactor->events[checkpos].fd);
    345. printf("[fd=%d] timeout\n", reactor->events[checkpos].fd);
    346. nty_event_del(reactor->epfd, &reactor->events[checkpos]);
    347. }
    348. }
    349. */
    350. int nready = epoll_wait(reactor->epfd, events, MAX_EPOLL_EVENTS, 1000);
    351. if (nready < 0) {
    352. printf("epoll_wait error, exit\n");
    353. continue;
    354. }
    355. for (i = 0;i < nready;i ++) {
    356. struct ntyevent *ev = (struct ntyevent*)events[i].data.ptr;
    357. if ((events[i].events & EPOLLIN) && (ev->events & EPOLLIN)) {
    358. ev->callback(ev->fd, events[i].events, ev->arg);
    359. }
    360. if ((events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)) {
    361. ev->callback(ev->fd, events[i].events, ev->arg);
    362. }
    363. }
    364. }
    365. }
    366. // 3, 6w, 1, 100 ==
    367. // <remoteip, remoteport, localip, localport>
    368. int main(int argc, char *argv[]) {
    369. unsigned short port = SERVER_PORT; // listen 8888
    370. if (argc == 2) {
    371. port = atoi(argv[1]);
    372. }
    373. struct ntyreactor *reactor = (struct ntyreactor*)malloc(sizeof(struct ntyreactor));
    374. ntyreactor_init(reactor);
    375. int i = 0;
    376. int sockfds[PORT_COUNT] = {0};
    377. for (i = 0;i < PORT_COUNT;i ++) {
    378. sockfds[i] = init_sock(port+i);
    379. ntyreactor_addlistener(reactor, sockfds[i], accept_cb);
    380. }
    381. ntyreactor_run(reactor);
    382. ntyreactor_destory(reactor);
    383. for (i = 0;i < PORT_COUNT;i ++) {
    384. close(sockfds[i]);
    385. }
    386. free(reactor);
    387. return 0;
    388. }

    参考博客:http/https服务器实现 - 放弃吧 - 博客园

    到此这篇关于http/https服务器实现的文章就介绍到这了,更多相关内容请搜索开发狮以前的文章,希望大家以后多多支持开发狮哦~

  • 相关阅读:
    vue防止用户连续点击造成多次提交
    JZM-D30室温探针台技术参数
    打工人都觉得香的 Java 程序员 306 道面试秘笈
    『 CSS实战』CSS3 实现一些好玩的效果(2)
    线性表的概念
    JVM调优-GC基本原理和调优关键分析
    2.6W字系统总结,带你实现 Linux 自由!
    陈吉宁经典演讲:平庸与卓越的差别
    DNS(二)
    【ES6】阮一峰ES6学习(一) let、const、解构赋值
  • 原文地址:https://blog.csdn.net/m0_58687318/article/details/126645087