{"id":13906735,"url":"https://github.com/Dungyichao/http_server","last_synced_at":"2025-07-18T04:33:05.177Z","repository":{"id":46943199,"uuid":"254070633","full_name":"Dungyichao/http_server","owner":"Dungyichao","description":"Fully functional web server using C/C++ from scratch without third party library","archived":false,"fork":false,"pushed_at":"2024-03-16T02:42:58.000Z","size":91865,"stargazers_count":271,"open_issues_count":1,"forks_count":43,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-08-07T23:49:01.394Z","etag":null,"topics":["c","c-plus-plus","css","ffmpeg","hls-live-streaming","html","http","http-server","javascript","linux","m3u8","mjpeg","nodejs","rapivid","raspivid","ts","ubuntu"],"latest_commit_sha":null,"homepage":"https://npcasc2020.web.app/","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Dungyichao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-04-08T11:38:14.000Z","updated_at":"2024-08-03T22:29:40.000Z","dependencies_parsed_at":"2024-01-19T10:23:04.027Z","dependency_job_id":null,"html_url":"https://github.com/Dungyichao/http_server","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dungyichao%2Fhttp_server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dungyichao%2Fhttp_server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dungyichao%2Fhttp_server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Dungyichao%2Fhttp_server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Dungyichao","download_url":"https://codeload.github.com/Dungyichao/http_server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226353462,"owners_count":17611708,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","c-plus-plus","css","ffmpeg","hls-live-streaming","html","http","http-server","javascript","linux","m3u8","mjpeg","nodejs","rapivid","raspivid","ts","ubuntu"],"created_at":"2024-08-06T23:01:41.549Z","updated_at":"2025-07-18T04:33:05.158Z","avatar_url":"https://github.com/Dungyichao.png","language":"C++","readme":"# Simple Http Web Server in Linux using C/C++ from Scratch\nIn this tutorial, we will demonstrate how to build a http web server from scratch without using any third party library. Please go through a good reading resource first: \n[Medium link](https://medium.com/from-the-scratch/http-server-what-do-you-need-to-know-to-build-a-simple-http-server-from-scratch-d1ef8945e4fa)\n, or you can read from the pdf version provided in this tutorial (\n[pdf link](https://github.com/Dungyichao/http_server/blob/master/doc/HTTP%20Server_%20Everything%20you%20need%20to%20know%20to%20Build%20a%20simple%20HTTP%20server%20from%20scratch_pdf2.pdf)\n). The tutorial in the Medium post only gives you a abstract concept and simple implementation but the author doesn't finish it. \n\n\u003cb\u003eMy tutorial will show you how to make a fully functional web server in no more than 200 lines of code. \u003c/b\u003e I also provide ```Node.js``` javascript code of building a simpler web server in the Summary section. \u003cbr /\u003e\n\n1. [Basic Knowledge](https://github.com/Dungyichao/http_server/blob/master/README.md#1-basic-knowledge-)\n2. [Overview](https://github.com/Dungyichao/http_server/blob/master/README.md#2-overview)\n    * 2.1 [System Requirement](https://github.com/Dungyichao/http_server/blob/master/README.md#21-system-requirement) \n    * 2.2 [Process Elements](https://github.com/Dungyichao/http_server/blob/master/README.md#22-process-elements)     \n3. [Implement the Code](https://github.com/Dungyichao/http_server/blob/master/README.md#3-implement-the-code)\n    * 3.1 [Code Structure](https://github.com/Dungyichao/http_server/blob/master/README.md#31-code-structure)\n    * 3.2 [Parse the Request from the Client](https://github.com/Dungyichao/http_server/blob/master/README.md#32-parse-the-request-from-the-client) \n    * 3.3 [Classify the Request](https://github.com/Dungyichao/http_server/blob/master/README.md#33-classify-the-request) \n    * 3.4 [Reply to the Client](https://github.com/Dungyichao/http_server/blob/master/README.md#34-reply-to-the-client)   \n    * 3.5 [Create Child Process to Handle Clients](https://github.com/Dungyichao/http_server/blob/master/README.md#35-create-child-process-to-handle-clients)  \n4. [Summary (with javascript)](https://github.com/Dungyichao/http_server/blob/master/README.md#4-summary)\n5. [Video Streaming Protocols](https://github.com/Dungyichao/http_server/blob/master/README.md#3-implement-the-code)\n    * 5.1 [HTTP Live Streaming (HLS)](https://github.com/Dungyichao/http_server/blob/master/README.md#51-http-live-streaming-hls)\n        - 5.1.1 [HLS Streaming Project](https://github.com/Dungyichao/http_server/blob/master/README.md#511-hls-streaming-project)\n    * 5.2 [MJPEG Streaming](https://github.com/Dungyichao/http_server/blob/master/README.md#52-mjpeg)\n        - 5.2.1 [MJPEG Streaming Project](https://github.com/Dungyichao/http_server/blob/master/README.md#521-mjpeg-streaming-project)\n6. [Advance Topic](https://github.com/Dungyichao/http_server/blob/master/README.md#6-advance-topic)\n    * 6.1 [Web Remote Control Robot](https://github.com/Dungyichao/Web-Remote-Control-Robot)\n7. [Make HTML More Organized](https://github.com/Dungyichao/http_server/blob/master/README.md#7-make-html-more-organized)\n    * 7.1 [Implement the Code](https://github.com/Dungyichao/http_server/tree/master#71-implement-the-code)\n    * 7.2 [Bonus: Bingo Game](https://github.com/Dungyichao/http_server/tree/master#72-bonus-bingo-game)\n\n# 1. Basic Knowledge \u003cbr /\u003e\nIn the internet world, there is always a server who can serve multiple clients. For example, Google, Netflix, Facebook... and so on are servers. People like us are client and we can use web browser (Chrome, Edge, Opera, Firefox....) to communicate with servers. \u003cbr /\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/server-client-role.JPG\" height=\"100%\" width=\"100%\"\u003e  \n\u003c/p\u003e\n\nYou can make a web server at your home and use your own laptop to access the server through LAN which stands for Local Area Network (having a Wi-Fi router can create a LAN at your home). However, if your html file includes some resources in WAN (Wide Area Network), then you need to be able to access the internet for displaying your html correctly.\n\nWhat you need is at least one PC or laptop (acts as server) running in Linux (\n[Ubuntu](https://ubuntu.com/desktop)\nor Debian) which should connect to the router. You can use cell phone as a client.  \n\n# 2. Overview\nWe are going to implement code for a http server on Ubuntu Desktop. Please follow the \u003cb\u003eVisual Studio Code\u003c/b\u003e official website to create a project (\n[link](https://code.visualstudio.com/docs/cpp/config-linux)\n). Download the web content (Demo website: https://npcasc2020.firebaseapp.com/)  which provide to you in this tutorial folder src (\n[link](https://github.com/Dungyichao/http_server/blob/master/src/Web_Content_1.zip)\n). Unzip the content and put all the content into your code project. It will be like the following image. (Notice that we do all the coding and compiling on Ubuntu Desktop)\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/project_folder.JPG\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\nCopy paste the code provided in this tutorial (\n[link](https://github.com/Dungyichao/http_server/blob/master/src/helloworld.cpp)\n) into the helloworld.cpp file. Compile the code and execute it. \n\nThe local ip address of my web server is 172.16.216.205, Subnet Mask is 255.255.0.0, the default gateway should be the ip address of your router , in our case is 172.16.216.6. \u003cb\u003eModify these number to fit in your case.\u003c/b\u003e If everything is working properly, now you can type in \u003cb\u003e172.16.216.205:8080\u003c/b\u003e in the browser on your laptop or cellphone (which should connect to Wi-Fi router at your home). What you see in the browser should be the same as the following animation.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/webpagedemo1.gif\" height=\"95%\" width=\"95%\"\u003e  \n\u003c/p\u003e\n\nI made this website (hosted on \n[Google Firebase](https://firebase.google.com/)\n) for the activity in our company (Nan Ya Plastics Corp. America which HQ in \u003cb\u003eTaiwan\u003c/b\u003e) to celebrate 2020 Chinese New Year. The template is from https://startbootstrap.com/theme/agency/\n\n## 2.1 System Requirement\n\u003cp align=\"center\"\u003e\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth align=\"center\"\u003eRole\u003c/th\u003e\n            \u003cth align=\"center\"\u003eRequirement\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003eWeb Server\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eLinux OS such as \u003cb\u003eUbuntu\u003c/b\u003e or \u003cb\u003eDebian\u003c/b\u003e. \u003cbr /\u003eC\\C++ development environment: \u003cb\u003eVisual Studio Code \u003c/b\u003eor \u003cb\u003eGeany\u003c/b\u003e. (Raspberry pi maybe not a good idea, it can serve the website but it would hang in the middle of transfering large image.)\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003eClient\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eWhatever OS (Windows, IOS, Android, Ubuntu) which is able to access web browser is good. You can use your cell phone as well.\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/p\u003e\n\n## 2.2 Process Elements\nThe following image is basically what we are going to implement in the code. We obmit some initialization part which was mentioned in the Meduim article (\n[link](https://medium.com/from-the-scratch/http-server-what-do-you-need-to-know-to-build-a-simple-http-server-from-scratch-d1ef8945e4fa)\n), however, you can still find it in our code.\n\u003cbr /\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/process_element1.jpg\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\nThe story is, the server keep listening any message it received, then we need to analyze what the useful information in the message by parsing it. The useful information we care about is the file name (with path) and file extension. The server then open the file according to the path and put the content of the file into a reply-message which we will later send to the client. Before sending the reply-message, we should first tell the client what kind of file content type we are going to send, maybe image file (.jpg, .png, ...) or txt file (.html, .doc, ...) and so on (refer to https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types), then we can send the reply-message (content of file) to the client. \n\n# 3. Implement the Code\nThe overall code can be viewed from the following link: https://github.com/Dungyichao/http_server/blob/master/src/helloworld.cpp\n\nAfter running the code, and then enter the ip address and port number in the web browser, you will see the following animation in your terminal\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/runcode.gif\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\n## 3.1 Code Structure\nWe keep looping through the following code in sequence, namely 1 --\u003e 2 --\u003e 3 --\u003e 4 (a) --\u003e 5 --\u003e 1 --\u003e 2 --\u003e 3 --\u003e 4 (d) --\u003e 5.....  We only focus on number 3 and number 4 and the reply function as well. \u003cbr /\u003e\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/code_struct.JPG\" height=\"75%\" width=\"75%\"\u003e  \n\u003c/p\u003e\n\n## 3.2 Parse the Request from the Client\nLet's take a look at what the \u003cb\u003every first\u003c/b\u003e request information the client sends to you \n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/http_request_0.JPG\" height=\"95%\" width=\"95%\"\u003e  \n\u003c/p\u003e\nAt first glance, it contains useless information (maybe not true for Hacker), how about we look at the other request information?\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/http_request_img.JPG\" height=\"95%\" width=\"95%\"\u003e  \n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/http_request_js.JPG\" height=\"95%\" width=\"95%\"\u003e  \n\u003c/p\u003e \nOK ! I think you nail it. The information between GET and HTTP/1.1. That is the file path which the client requires to display the website correctly on it's browser. \u003cbr /\u003e\u003cbr /\u003e\n\nThe \u003cb\u003eparse function\u003c/b\u003e just retrieves the \u003cb\u003epath\u003c/b\u003e and \u003cb\u003efile extension\u003c/b\u003e (such as .jpg  .html  .css....) from a bunch of information. \u003cbr /\u003e \n```c++\nchar* parse(char line[], const char symbol[])\n{\n    char *message;\n    char * token = strtok(line, symbol);\n    int current = 0;\n\n    while( token != NULL ) {\n      \n      token = strtok(NULL, \" \");\n      if(current == 0){\n          message = token;\n          return message;\n      }\n      current = current + 1;\n   }\n   return message;\n}\n```\n\n## 3.3 Classify the Request \nIn \n[section 2.2 Process Element](https://github.com/Dungyichao/http_server#22-process-elements)\n we mention that we need to tell the client what kind of content we are going to send in. The classification is just a bunch of \u003cb\u003eif else\u003c/b\u003e logic detemination according to the file extension from the \u003cb\u003eparsed\u003c/b\u003e information (section 3.2). I just list the partial code in the following to give you some concept.\n \n ```c++\n if(strlen(parse_string) \u003c= 1){\n            //case that the parse_string = \"/\"  --\u003e Send index.html file\n            //write(new_socket , httpHeader , strlen(httpHeader));\n            char path_head[500] = \".\";\n            strcat(path_head, \"/index.html\");\n            strcat(copy_head, \"Content-Type: text/html\\r\\n\\r\\n\");\n            send_message(new_socket, path_head, copy_head);\n}\nelse if ((parse_ext[0] == 'j' \u0026\u0026 parse_ext[1] == 'p' \u0026\u0026 parse_ext[2] == 'g') || \n(parse_ext[0] == 'J' \u0026\u0026 parse_ext[1] == 'P' \u0026\u0026 parse_ext[2] == 'G'))\n{\n            //send image to client\n            char path_head[500] = \".\";\n            strcat(path_head, parse_string);\n            strcat(copy_head, \"Content-Type: image/jpeg\\r\\n\\r\\n\");\n            send_message(new_socket, path_head, copy_head);\n}\nelse if (parse_ext[strlen(parse_ext)-2] == 'j' \u0026\u0026 parse_ext[strlen(parse_ext)-1] == 's')\n{\n            //javascript\n            char path_head[500] = \".\";\n            strcat(path_head, parse_string);\n            strcat(copy_head, \"Content-Type: text/javascript\\r\\n\\r\\n\");\n            send_message(new_socket, path_head, copy_head);\n}\nelse if (parse_ext[strlen(parse_ext)-3] == 'c' \u0026\u0026 parse_ext[strlen(parse_ext)-2] == 's' \n\u0026\u0026 parse_ext[strlen(parse_ext)-1] == 's')\n{\n            //css\n            char path_head[500] = \".\";\n            strcat(path_head, parse_string);\n            strcat(copy_head, \"Content-Type: text/css\\r\\n\\r\\n\");\n            send_message(new_socket, path_head, copy_head);\n}\nelse if (parse_ext[0] == 'i' \u0026\u0026 parse_ext[1] == 'c' \u0026\u0026 parse_ext[2] == 'o')\n{\n            //https://www.cisco.com/c/en/us/support/docs/security/web-security-appliance/117995-qna-wsa-00.html\n            char path_head[500] = \".\";\n            strcat(path_head, \"/img/favicon.png\");\n            strcat(copy_head, \"Content-Type: image/vnd.microsoft.icon\\r\\n\\r\\n\");\n            send_message(new_socket, path_head, copy_head);\n}\n ```\n I know you are still wondering the very first request information I mentioned in section 3.2 which contains ```/``` such a useless information. Actually, it does give us a hint to send it our web page, namely ```index.html```. The client will receive the html file looks like the following\n \n \u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/index_html.JPG\" height=\"95%\" width=\"95%\"\u003e  \n\u003c/p\u003e\n\nThe client's web browser will read line by line and do whatever the html file tells it. When it reads until line 14 (in above image), the client will send request to the server to ask for ```vendor/fontawesome-free/css/all.min.css``` which is a css file. Server than ```parse``` the request, and then classify the request. \n\nThere are multiple file extension we need to take good care of, the following link shows you a list of file extension: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types . We need to first notify the client what kind of content we are going to send so that the client can receive the content accordingly. The notification message looks like the following:\n\n```c++\nHTTP/1.1 200 Ok\\r\\n\nContent-Type: text/html\\r\\n\\r\\n\n```\nYou need to replace the ```text/html``` with the proper MIME Type according to the file extension. \n\nWhile writing this tutorial, a special file extension request from the client ```/favicon.ico```, however, I couldn't find out the file in my website at all (I also look into all html, css, js files). It turns out that every browser will automatically request for ```/favicon.ico``` which is merely an icon for displaying on the browser tab shown in the following. So what you need is just reply a .ico or .png file to the client.\n \u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/ico.JPG\" height=\"95%\" width=\"95%\"\u003e  \n\u003c/p\u003e\n\nHere we list out some common file extension and their MIME Type.\n\n\u003cp align=\"center\"\u003e\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth align=\"center\"\u003eFile Extension\u003c/th\u003e\n            \u003cth align=\"center\"\u003eMIME Type\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.css\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003etext/css\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.html\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003etext/html\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.ico\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eimage/vnd.microsoft.icon\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.jpg\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eimage/jpeg\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.js\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003etext/javascript\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.json\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eapplication/json\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.ttf\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003efont/ttf\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.txt\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003etext/plain\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.woff\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003efont/woff\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.xml\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003etext/xml\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.mp3\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eaudio/mpeg\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.mpeg\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003evideo/mpeg\u003c/td\u003e\n        \u003c/tr\u003e\n       \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.m3u8\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eapplication/vnd.apple.mpegurl\u003c/td\u003e\n        \u003c/tr\u003e\n       \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e.ts\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003evideo/mp2t\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/p\u003e\n \n## 3.4 Reply to the Client\nThe following function first send notification message to the client and let it knows what kind of content we are going to send (section 3.3). We then open the file using ```open``` and retrieve information of the file (not the content) using ```fstat``` and store in ```stat object```. Lastly, we read the file content and send the content using ```sendfile```. Because some file might be too large to send in one message, thus, we need to send the content pices by pices (size = block_size).\n\n```c++\nint send_message(int fd, char image_path[], char head[]){\n\n    struct stat stat_buf;  /* hold information about input file */\n\n    write(fd, head, strlen(head));\n\n    int fdimg = open(image_path, O_RDONLY);\n     \n    fstat(fdimg, \u0026stat_buf);\n    int img_total_size = stat_buf.st_size;\n    int block_size = stat_buf.st_blksize;\n\n    int sent_size;\n\n    while(img_total_size \u003e 0){\n        if(img_total_size \u003c block_size){\n            sent_size = sendfile(fd, fdimg, NULL, img_total_size);            \n        }\n        else{\n            sent_size = sendfile(fd, fdimg, NULL, block_size);\n        }       \n        printf(\"%d \\n\", sent_size);\n        img_total_size = img_total_size - sent_size;\n    }\n    close(fdimg);\n}\n```\nYou might not familiar with the above command, so the following link may help you.\n\n\u003cp align=\"center\"\u003e\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth align=\"center\"\u003eTerm\u003c/th\u003e\n            \u003cth align=\"center\"\u003eWeb Link\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003estat\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003ehttp://man7.org/linux/man-pages/man2/stat.2.html\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003esendfile\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003ehttp://man7.org/linux/man-pages/man2/sendfile.2.html \u003cbr /\u003e http://www.tldp.org/LDP/LG/issue91/tranter.html\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003efstat\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003ehttps://linux.die.net/man/2/fstat\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003eopen\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003ehttp://man7.org/linux/man-pages/man2/open.2.html\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/p\u003e\n\n## 3.5 Create Child Process to Handle Clients\nIn a real world server, we are not going to reply all connected client with only one process. Our server program will not have good performance when multiple clients connecting to us at once. So we will create child process whenever new client connected. Please read the tutorial [link](https://www.linuxhowtos.org/C_C++/socket.htm) ([PDF](https://github.com/Dungyichao/http_server/blob/master/doc/Sockets%20Tutorial.pdf)) - Enhancements to the server code part. \n\nWe modifiy a little bit code from the tutorial link. Please see the following. We only shows the while loop part.\n```c++\nwhile (1)\n {\n   newsockfd = accept(server_fd,\n               (struct sockaddr *) \u0026cli_addr, \u0026clilen);\n   if (newsockfd \u003c 0)\n     error(\"ERROR on accept\");\n   pid = fork();\n   if (pid \u003c 0){\n     error(\"ERROR on fork\");\n     exit(EXIT_FAILURE);  //We add this part\n    }\n   if (pid == 0)\n   {\n     //close(server_fd);    //We omint this part because it would cause error\n     ......................................\n     This part is parsing the message from client, read path file, write file back to client\n     ...\n     ....\n     .....\n     ......................................\n     close(new_socket);\n     exit(0);\n   }\n   else{\n            printf(\"\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003e\u003eParent create child with pid: %d \u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\u003c\", pid);\n            close(new_socket);\n   }\n } /* end o\n```\n\n# 4. Summary\nThis is a simple, experimental but functional Ubuntu web server. Some error protection method not included. Any advise are welcome. I also want to implment a \u003cb\u003ewebcam\u003c/b\u003e server sending real-time streaming. \n\nIs there a simple way? Yes, you can use \u003cb\u003e```Node.js```\u003c/b\u003e which is a JavaScript runtime environment where you can build a simple web server in about 60 lines of code. (Youtube Node.js Crash Course: https://www.youtube.com/watch?v=fBNz5xF-Kx4)\n```javascript\nconst http = require('http');\nconst path = require('path');\nconst fs = require('fs');\n\nconst server = http.createServer((req, res) =\u003e {\n    let filePath = path.join(__dirname, req.url === '/' ? 'index.html' : req.url);\n    let file_extname = path.extname(filePath);\n    let contentType = 'text/html';\n\n    switch(file_extname){\n        case '.js':\n            contentType = 'text/javascript';\n            break;\n        case '.css':\n            contentType = 'text/css';\n            break;\n        case '.json':\n            contentType = 'application/json';\n            break;\n        case '.png':\n            contentType = 'image/png';\n            break;\n        case '.JPG':\n            contentType = 'image/jpg';\n            break;\n        case '.ico':\n            filePath = path.join(__dirname,'favicon.png');\n            contentType = 'image/png';\n            break;\n        case '.ttf':\n            contentType = 'font/ttf';\n            break;\n        case '.woff':\n            contentType = 'font/woff';\n            break;\n        case '.woff2':\n            contentType = 'font/woff2';\n            break;\n    }\n    // Read File\n    fs.readFile(filePath, (err, content) =\u003e {\n        if(err){\n            if(err.code == 'ENOENT'){\n                console.log('Page not found');\n            }\n            else{\n                res.writeHead(500);\n                res.end('Server Error: ${err.code}');\n            }\n        }\n        else{\n            res.writeHead(200, {'Content-Type': contentType});\n            res.end(content);    \n        }\n    });\n});\n\nconst PORT = process.env.PORT || 8080;\n\nserver.listen(PORT, () =\u003e console.log(`Server is running and port is ${PORT}`));\n```\n\n# 5. Video Streaming Protocols\nThe following are some most common streaming protocols and most widely used in current time. However, we will only focus on the HLS.  \n\u003cp align=\"center\"\u003e\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth align=\"center\"\u003eProtocols\u003c/th\u003e\n            \u003cth align=\"center\"\u003eDetail\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003eReal-Time Messaging Protocol (RTMP)\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eToday it’s mostly used for ingesting live streams. In plain terms, when you set up your encoder to send your video feed to your video hosting platform, that video will reach the CDN via the RTMP protocol. However, that content eventually reaches the end viewer in another protocol – usually HLS streaming protocol.\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003eReal-Time Streaming Protocol (RTSP)\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eIt is a good choice for streaming use cases such as IP camera feeds (e.g. security cameras), IoT devices (e.g. laptop-controlled drone), and mobile SDKs.\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003eHTTP Live Streaming (HLS)\u003c/td\u003e\n            \u003ctd align=\"Left\"\u003eHLS is the most widely-used protocol today, and it’s robust. Currently, the only downside of HLS is that latency can be relatively high.\u003c/td\u003e\n        \u003c/tr\u003e        \n    \u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/p\u003e\n\n## 5.1 HTTP Live Streaming (HLS)\nReference link: \u003cbr /\u003e\nhttps://www.cloudflare.com/learning/video/what-is-http-live-streaming/ \u003cbr /\u003e\nhttps://www.dacast.com/blog/hls-streaming-protocol/\n\nStreaming is a way of delivering visual and audio media to users over the Internet. It works by continually sending the media file to a user's device a little bit at a time instead of all at once. With streaming over HTTP, the standard request-response pattern does not apply. \u003cb\u003eThe connection between client and server remains open for the duration of the stream\u003c/b\u003e, and the server pushes video data to the client so that the client does not have to request every segment of video data. HLS use TCP (more reliable) rather than UDP (more faster) as trasport protocols. \n\nFirst, the HLS protocol chops up MP4 video content into short (10-second) chunks with the .ts file extension (MPEG2 Transport Stream). Next, an HTTP server stores those streams, and HTTP delivers these short clips to viewers on their devices. Some software server creates an M3U8 playlist file (e.g. manifest file) that serves as an index for the video chunks. Some .m3u8 and .ts information can be found in the following link [link1](https://nagendrabandi.com/download-m3u8ts-file/#:~:text=A%20M3U8%20stands%20for%20MP3,Flash%20video%20format%20(flv).\u0026text=ts%20files%20are%20referenced%20in,M3U8%20playlist%20file%20index)([PDF](https://github.com/Dungyichao/http_server/blob/master/doc/How%20to%20download%20a%20m3u8.pdf)), [link2](https://datatracker.ietf.org/doc/html/rfc8216)\n\nHLS is compatible with a wide range of devices and firewalls. However, latency (or lag time) tends to be in the 15-30 second range with HLS live streams. \n\n### 5.1.1 HLS Streaming Project\nThere are two way to do this project. Please go to the following [link1]( https://five381.com/blog/2020-03/rpi-camera-rtmp-streaming/)([PDF](https://github.com/Dungyichao/http_server/blob/master/doc/STREAMING%20LIVE%20VIDEO%20WITH%20A%20RASPBERRY%20PI%20CAMERA%20OVER%20RTMP.pdf)) and follow the instructions.\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/rapivid_method.JPG\" height=\"95%\" width=\"95%\"\u003e  \n\u003c/p\u003e\nRapivid can output segment video files in local folder, however, in option 1, if not using Nginx, when stdout pipe into GStreamer to generate streaming files, it’s .ts file keep growing which never split into segment. It only generate .m3u8 playlist file when you stop the process. It requires to go through Nginx with rtmp sink to generate proper segment .ts files with playlist .m3u8. So we change to the option 2, which use ffmpeg to generate proper segment .ts files with playlist .m3u8. Finally, we can use our handmade http server to send out the .m3u8 and .ts files from local folder to the client browser for streaming. We shows the steps for option 2 below. \u003cbr /\u003e\n\nFirst we create the bash file\n```bash\n$ sudo nano /usr/local/bin/ffmpeg-rpi-stream\n```\nPlace the following into /usr/local/bin/ffmpeg-rpi-stream. Make it executable. Make sure your http server can access the video location (in the base option). Best way is to put handmade http server, index.html, and these .m3u8, .ts file into same location.\n```bash\n#!/bin/bash\n# /usr/local/bin/ffmpeg-rpi-stream\nbase=\"/home/pi/Desktop/http/video\"     \ncd $base\n\nraspivid -ih -t 0 -b 2097152 -w 1280 -h 720 -fps 30 -n -o - | \\\nffmpeg -y \\\n   -use_wallclock_as_timestamps 1 \\   #fix error: ffmpeg timestamps are unset in a packet for stream0. \n    -i - \\\n    -c:v copy \\\n    -map 0 \\\n    -f ssegment \\\n    -segment_time 1 \\\n    -segment_wrap 4 \\\n    -segment_format mpegts \\\n    -segment_list \"$base/s.m3u8\" \\\n    -segment_list_size 1 \\\n    -segment_list_flags live \\\n    -segment_list_type m3u8 \\\n    \"$base/s_%08d.ts\"\n\n```\nThe following table shows how your configuration would affect the streaming latency time in our project. (This table is based on our Raspberry Pi, camera and LAN speed)\n\u003cp align=\"center\"\u003e\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth align=\"center\"\u003eSegment_time\u003c/th\u003e\n            \u003cth align=\"center\"\u003eSegment_wrap\u003c/th\u003e\n            \u003cth align=\"center\"\u003eSegment_List_Size\u003c/th\u003e\n            \u003cth align=\"center\"\u003eLatency\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e1\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e2 ~ 20\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e1\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e3s ~ 5s\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e1\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e4\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e2\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e5s\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e1\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e20\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e2\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e6s\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e1\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e20\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e5 ~ 10\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e9s\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e2\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e4\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e1\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e3s ~ 4s\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e4\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e4\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e1\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e7s ~ 8s\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n            \u003ctd align=\"center\"\u003e4\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e4\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e2\u003c/td\u003e\n            \u003ctd align=\"center\"\u003e11s\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\u003c/p\u003e\n\nSegment_time means how long the .ts file (video length). Segment_wrap means how many .ts file will be kept. Segment_List_Size means how many .ts records will be kept in the .m3u8 which will affact client playback. Segment_wrap should be larger or equal to Segment_List_Size.\n\nMake it executable:\n```bash\n$sudo chmod +x /usr/local/bin/ffmpeg-rpi-stream\n```\nWe will create a systemd unit file to manage the gstreamer process. We'll configure it to automatically restart the stream if it goes down.\n```bash\n$sudo nano /lib/systemd/system/ffmpeg-rpi-stream.service\n```\nPlace the following into /lib/systemd/system/ffmpeg-rpi-stream.service\n```bash\n[Unit]\nDescription=RPI FFMpeg RTMP Source\n\n[Service]\nType=simple\nExecStart=/usr/local/bin/ffmpeg-rpi-stream\nRestart=on-failure\nRestartSec=5s\n\n[Install]\nWantedBy=multi-user.target\n```\nEnable and start the service:\n```bash\n$sudo systemctl daemon-reload\n$sudo systemctl enable ffmpeg-rpi-stream\n$sudo systemctl start ffmpeg-rpi-stream\n```\nNow, you can use browser to watch the stream of the raspberry pi camera. \nIf want to stop streaming camera service\n```bash\n$ ps aux\n```\nFind the PID (raspivid task)\n```bash\n$sudo kill -9 \u003cpid\u003e\n```\n## 5.2 MJPEG\nHLS is not a good idea for real-time streaming robot project. The latency is not acceptable if you try to remote control your robot. Therefore, we need someting more real time. MJPEG should be able to meet our requirement. MJPEG is mearly a series of JPEG files. A great open source project using C language called streamEye([link](https://github.com/ccrisan/streameye), [backup](https://github.com/Dungyichao/http_server/blob/master/Project/simple_streameye/streameye-master.zip)), and an online tutorial using Python language ([link](https://randomnerdtutorials.com/video-streaming-with-raspberry-pi-camera/), [PDF](https://github.com/Dungyichao/http_server/blob/master/doc/Tutorial%20-%20Video%20Streaming%20with%20Raspberry%20Pi%20Camera.pdf))  are a good starting point. The following project is based on these two online source.\n\n### 5.2.1 MJPEG Streaming Project\nLet's take a look at the system structure of StreamEye. Python will be used to capture JPEG image file, and then output to StreamEye.o for further processing, and then act as a http server waiting client to connect and reply with a series of JPEG data.\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/streameye_system.JPG\" height=\"75%\" width=\"75%\"\u003e  \n\u003c/p\u003e\nI modify the Python, and C code from StreamEye and make it more simpler (less user option, less function) so that we can have a better understanding of the concept.\u003cbr /\u003e\n\u003cbr /\u003e\n\nPlease go to Project folder ([link](https://github.com/Dungyichao/http_server/tree/master/Project/simple_streameye)) and download ```rasp_test.py``` and ```test001.c``` and put in whatever your project folder in rasperrypi. Use Geany to open test001.c, click on Set Build Command ([reference](https://wiki.geany.org/howtos/configurebuildmenu)) and input like the following\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/set_build_command.JPG\" height=\"50%\" width=\"50%\"\u003e  \n\u003c/p\u003e\nClick on build. After successfully building the c code, open command prompt, cd to your project folder, enter the following command\n\n```bash\n$ python rasp_test.py | ./test001\n```\n\nNotice that, in test001.c, we've defined the port to 8084, so you can now open web broswer on other PC (in the same network as raspberrypi) and enter address. In my case, my raspberrypi IP is 172.16.216.206, so I put 172.16.216.206:8084 in my web browser to see the stream. \n\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/mjpeg-stream.gif\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\nIn above GIF, the raspberrypi is connected to WIFI while my PC is wired connect to network hub.\u003cbr /\u003e\n\u003cbr /\u003e\n\nIf you have other web server servering an index.html which web page contain the MJPEG streaming, you can put the following html tag inside the index.html. \n```html\n\u003cimg src=\"http://172.16.216.206:8084/stream.mjpg\" width=\"320\" height=\"240\"\u003e\n```\nIn my case, I run the web server and streaming server on the same raspberry pi (same ip, but different port). Both program run at the same time. There is no CROS problem because they are in the same domain.\n\nI made a document of my troubleshooting process and answer in this ([link](https://github.com/Dungyichao/http_server/blob/master/Project/simple_streameye/Problem%20and%20answer%20-%20StreamEye%20-%2020220218.pdf)) talking about SIGPIPE, EPIPE, errno, nonblocking Socket, pthread, realloc(), pointer arithmetic, MJPEG parsing.\n\n# 6. Advance Topic\nBy using our hand made http server, we can implement some interesting project.\n\n## 6.1 Web Remote Control Robot\nhttps://github.com/Dungyichao/Web-Remote-Control-Robot\n\n# 7. Make HTML More Organized\nRecently, I made a new Bingo game in the website for our company's Chinese New Year, and the code is getting bigger and larger. I can no longer maintain all the code in just one index.html or one javascript file. The idea is to spread all components into different HTML files, and import these html files into the main index.html. From the following picture, you can see I organize HTML, javascript, images, css files into its folders.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/organize_html_folders.JPG\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\n## 7.1 Implement the Code\nYou can see the source code in this link ([link](https://github.com/Dungyichao/http_server/blob/master/src/Web_Content_2.zip)). The rough idea can be shown in the following code\n\nThis is where Javascript function will load child HTML files into this main index.html.\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/index_head_load.JPG\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\nThis is where child HTML files content will be loaded and displayed. Because the browser will read line by line, so the order in the following will be reflected on the website. Actually, those div tag just act like a place holder, the browser will literally insert all the loaded HTML code into these place holder (reference by the id). However, I cannot move the Navigation bar away to separate HTML file. I do not know the reason and cannot find any solution.\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/index_body_div_id.JPG\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\nThis is where the browser will load all Javascript files\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/index_body_js.JPG\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\nThis is just a regular html code where I remove from original index.html and paste the content into separate html file. The following is just one of the example. You can find the rest in the zip file\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/video_html.JPG\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\nAfter doing all of this, our web content displayed the same information, but our index.html is more cleaner and more easy to manage. \n\n## 7.2 Bonus: Bingo Game\nThis year 2024, I added another Bingo game which allow user to input their bingo, submit to firebase. The firebase administrator will input the called number online. Use can refresh the browser and see each user's name and their number of lines. \n\nPlayer Input Demo\nhttps://github.com/Dungyichao/http_server/assets/25232370/62d29331-899e-49ab-95ad-195f5b63c431\n\nhttps://user-images.githubusercontent.com/25232370/62d29331-899e-49ab-95ad-195f5b63c431.mp4\n\nThis is player input page\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/Bingo_user_input.JPG\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\nThis is player score\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"/img/Bingo_score.JPG\" height=\"90%\" width=\"90%\"\u003e  \n\u003c/p\u003e\n\nAlgorithm to calculate Bingo Game match lines. You can find the code implementation in the src/Web_Content_2.zip js folder Refresh_Bingo_Score.js. \n```html\n1. create an empty 1-D array which is the same number as player bingo input (m x m)\n2. check player's input, if match, insert 1 into array, otherwise, insert 0 into array\n3. Check row by row, column by column, two diagonal. If line added up to m, player matched line plus one\n4. Continue to check next player\n```\n","funding_links":[],"categories":["HarmonyOS"],"sub_categories":["Windows Manager"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDungyichao%2Fhttp_server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FDungyichao%2Fhttp_server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FDungyichao%2Fhttp_server/lists"}