{"id":852,"date":"2022-05-22T16:56:27","date_gmt":"2022-05-22T07:56:27","guid":{"rendered":"https:\/\/pg-mana.net\/blog\/?p=852"},"modified":"2024-09-09T17:33:32","modified_gmt":"2024-09-09T08:33:32","slug":"mini-web-server","status":"publish","type":"post","link":"https:\/\/pg-mana.net\/blog\/mini-web-server\/","title":{"rendered":"Mini Web Server\u3092C\u8a00\u8a9e\u3067\u66f8\u3044\u305f"},"content":{"rendered":"\n<p>\u81ea\u4f5cOS\u3067open\u3068\u304bread\u306eSystemCall\u3092\u5b9f\u88c5\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u4f55\u304b\u9762\u767d\u3044\u3082\u306e\u3092\u4f5c\u308a\u305f\u304f\u306a\u3063\u305f\u306e\u3067\u3001\u6700\u8fd1\u306e\u81ea\u4f5cOS\u3067\u306f\u4e00\u3064\u306e\u76ee\u6a19(?)\u3068\u3055\u308c\u3066\u3044\u308bWeb\u30b5\u30fc\u30d0\u3092\u52d5\u304b\u3059\u3053\u3068\u3092\u76ee\u6a19\u3068\u3059\u308b\u3053\u3068\u306b\u3057\u307e\u3057\u305f\u3002<br>\u3068\u308a\u3042\u3048\u305a\u4f7f\u7528\u3059\u308b\u30b7\u30b9\u30c6\u30e0\u30b3\u30fc\u30eb\u3092\u63a2\u308b\u305f\u3081\u306bC\u8a00\u8a9e\u3067\u8d85\u7c21\u6613\u7248\u306eWeb Server\u3092\u66f8\u3044\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>\u4f7f\u7528\u3059\u308bSystemCall\u3092\u6700\u5c0f\u9650\u306b\u3059\u308b\u305f\u3081\u306bfopen\u3084malloc\u306a\u3069\u306f\u4f7f\u7528\u305b\u305a\u3001open\/read\u306a\u3069\u306eSystemCall\u306b\u8fd1\u3044\u95a2\u6570\u306e\u307f\u4f7f\u7528\u3059\u308b\u3088\u3046\u306b\u3057\u307e\u3057\u305f\u3002\u672c\u5f53\u306fmalloc\u306f\u65e2\u306bOS\u5074\u3067\u30e1\u30e2\u30ea\u7ba1\u7406\u304c\u3067\u304d\u3066\u3044\u308b\u306e\u3067\u4f7f\u3044\u305f\u304b\u3063\u305f\u306e\u3067\u3059\u304c\u3053\u306e\u4e16\u306eLinux\u5411\u3051\u306elibc\u5b9f\u88c5\u306f\u30e1\u30e2\u30ea\u3092\u78ba\u4fdd\u3059\u308b\u969b\u306bbrk\u3084mprotect\u3092\u4f7f\u7528\u3059\u308b\u3089\u3057\u304f\u3001\u73fe\u5728\u306e\u81ea\u5206\u306eOS\u3067\u306f\u7d06\u4f59\u66f2\u6298\u3042\u3063\u3066Linux ABI\u4e92\u63db\u3067\u3001\u3053\u308c\u3089\u306e\u5b9f\u88c5\u304c\u3084\u3084\u9762\u5012\u3060\u3063\u305f\u306e\u3067\uff08\u9811\u5f35\u308c\u3070\u3067\u304d\u306a\u3044\u3053\u3068\u306f\u306a\u3044\u304c)\u3001\u3068\u308a\u3042\u3048\u305a\u7aef\u6298\u308b\u3053\u3068\u306b\u3057\u307e\u3057\u305f\u3002<\/p>\n\n\n\n<p>\u30b3\u30fc\u30c9\u306f\u4ee5\u4e0b\u306e\u3068\u304a\u308a\u3067\u3059\u3002<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include &lt;fcntl.h&gt;\n#include &lt;netinet\/in.h&gt;\n#include &lt;stdio.h&gt;\n#include &lt;string.h&gt;\n#include &lt;sys\/socket.h&gt;\n#include &lt;unistd.h&gt;\n\n\/\/#define DEBUG\n\n#ifdef DEBUG\n#include &lt;arpa\/inet.h&gt;\n#endif\n\n#define HTTP_VERSION \"HTTP\/1.1\"\n#define GET_METHOD \"GET\"\n#define SERVER_HEADER_ENTRY \"Server: Mini Web Server\"\n#define HTTP_200 HTTP_VERSION \" 200 OK\"\n#define HTTP_404 HTTP_VERSION \" 404 Not Found\"\n#define HTTP_500 HTTP_VERSION \" 500 Internal Server Error\"\n\nint main() {\n  puts(\"Mini Web Server\");\n\n  int receive_socket = socket(AF_INET, SOCK_STREAM, 0);\n  if (receive_socket &lt; 0) {\n    fprintf(stderr, \"Failed to open the socket(ret: %d)\\n\", receive_socket);\n    return 1;\n  }\n\n  struct sockaddr_in host;\n  host.sin_family = AF_INET;\n  host.sin_port = htons(8080);\n  host.sin_addr.s_addr = INADDR_ANY;\n  if (bind(receive_socket, (struct sockaddr *)&amp;host, sizeof(host)) &lt; 0) {\n    fprintf(stderr, \"Failed to bind\\n\");\n    return 1;\n  }\n\n  if (listen(receive_socket, 10) &lt; 0) {\n    fprintf(stderr, \"Failed to listen the socket.\\n\");\n    return 1;\n  }\n\n  while (1) {\n    struct sockaddr_in client_address;\n    socklen_t client_address_length;\n    int client_socket =\n        accept(receive_socket, (struct sockaddr *)&amp;client_address,\n               &amp;client_address_length);\n#ifdef DEBUG\n    printf(\"Client: {\\\"Address\\\": \\\"%s\\\", \\\"Port\\\": %d}\\n\",\n           inet_ntoa(client_address.sin_addr), client_address.sin_port);\n#endif\n    char buffer&#91;0x1000];\n    buffer&#91;sizeof(buffer) - 1] = '\\0';\n\n    int received = recv(client_socket, buffer, sizeof(buffer), 0);\n    if (received &lt; 0) {\n      fprintf(stderr, \"Failed to receive data(ret: %d)\\n\", received);\n      return 1;\n    }\n\n    \/* Check method *\/\n    if (received &lt;= (sizeof(GET_METHOD) - 1) ||\n        strncmp(buffer, GET_METHOD, sizeof(GET_METHOD) - 1) != 0) {\n      close(client_socket);\n      continue;\n    }\n    size_t pointer = sizeof(GET_METHOD) - 1;\n\n    if (buffer&#91;pointer] != ' ' || buffer&#91;pointer + 1] != '\/') {\n      close(client_socket);\n      continue;\n    }\n    pointer += 1;\n    \/* remove \"\/\"(root) *\/\n    pointer += 1;\n    char *file_name = buffer + pointer;\n    size_t file_name_size = 0;\n    for (; (pointer + file_name_size) &lt; received &amp;&amp;\n           buffer&#91;pointer + file_name_size] != ' ';\n         file_name_size++)\n      ;\n    pointer += file_name_size + 1;\n\n    if (received &lt;= (pointer + sizeof(HTTP_VERSION) - 1) ||\n        strncmp(buffer + pointer, HTTP_VERSION, sizeof(HTTP_VERSION) - 1) !=\n            0) {\n      close(client_socket);\n      continue;\n    }\n    if (file_name_size == 0) {\n      const char index_name&#91;] = \"index.htm\";\n      strcpy(file_name, index_name);\n      file_name_size = sizeof(index_name) - 1;\n    }\n    file_name&#91;file_name_size] = '\\0';\n#ifdef DEBUG\n    printf(\"URL: %s\\n\", file_name);\n#endif\n    \/* Create Response *\/\n    int fd = open(file_name, O_RDONLY);\n    if (fd &lt; 0) {\n      const char not_found_text&#91;] =\n          HTTP_404 \"\\r\\n\" SERVER_HEADER_ENTRY \"\\r\\n\\r\\nFile is not found.\";\n      send(client_socket, not_found_text, sizeof(not_found_text) - 1, 0);\n    } else {\n      size_t size = lseek(fd, 0, SEEK_END);\n      lseek(fd, 0, SEEK_SET);\n      if (size &gt; sizeof(buffer)) {\n        const char error_text&#91;] =\n            HTTP_500 \"\\r\\n\" SERVER_HEADER_ENTRY\n                     \"\\r\\n\\r\\nFile size is exceeded the buffer size.\";\n        send(client_socket, error_text, sizeof(error_text) - 1, 0);\n      } else {\n        sprintf(buffer,\n                HTTP_200 \"\\r\\n\" SERVER_HEADER_ENTRY\n                         \"\\r\\nContent-Length: %zu\\r\\n\\r\\n\",\n                size);\n        send(client_socket, buffer, strlen(buffer), 0);\n        read(fd, buffer, size);\n        send(client_socket, buffer, size, 0);\n      }\n    }\n    close(client_socket);\n  }\n  return 0;\n}<\/code><\/pre>\n\n\n\n<p>strace\u3067\u547c\u3070\u308c\u3066\u3044\u308b\u30b7\u30b9\u30c6\u30e0\u30b3\u30fc\u30eb\u3092\u78ba\u8a8d\u3059\u308b\u3068\u8d77\u52d5\u51e6\u7406\u4ee5\u5916\u3067\u306f\u3001<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>wrtiev(puts, fprintf)<\/li>\n\n\n\n<li>socket<\/li>\n\n\n\n<li>bind<\/li>\n\n\n\n<li>listen<\/li>\n\n\n\n<li>accept<\/li>\n\n\n\n<li>recvfrom<\/li>\n\n\n\n<li>open<\/li>\n\n\n\n<li>lseek<\/li>\n\n\n\n<li>sendto<\/li>\n\n\n\n<li>read<\/li>\n\n\n\n<li>close<\/li>\n<\/ul>\n\n\n\n<p>\u306e\u307f\u3068\u306a\u3063\u3066\u307e\u3059\u3002<\/p>\n\n\n\n<p>\u3068\u308a\u3042\u3048\u305aLinux\u3067\u30d3\u30eb\u30c9\u3057\u305f\u3068\u3053\u308d\u307e\u3042\u307e\u3042\u52d5\u3044\u3066\u3044\u308b\u3088\u3046\u306e\u306a\u306e\u3067\u3053\u308c\u304c\u52d5\u304f\u3088\u3046\u306b\u9811\u5f35\u308a\u307e\u3059\u3002<br><br>\u3068\u8a00\u3063\u3066\u3082\u3001\u307e\u305a\u306f\u30cd\u30c3\u30c8\u30ef\u30fc\u30af\u30c7\u30d0\u30a4\u30b9\u306e\u30c9\u30e9\u30a4\u30d0\u66f8\u304f\u3068\u3053\u308d\u304b\u3089\u59cb\u3081\u306a\u3044\u3068\u3044\u3051\u306a\u3044\u306e\u3067\u3059\u304c&#8230;<\/p>\n\n\n\n<p>\u8ffd\u8a18: \u4e00\u5fdc\u52d5\u304d\u307e\u3057\u305f\u3002 <\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"twitter-tweet\" data-width=\"500\" data-dnt=\"true\"><p lang=\"ja\" dir=\"ltr\">\u571f\u65e5\u3068\u5168\u4f11\u306e\u6708\u66dc\u65e5\u3092\u6d88\u8cbb\u3057\u3066Methylenix\u306eTCP\u901a\u4fe1\u306e\u3059\u3079\u3066\u3092\u5b9f\u88c5\u3057\u305f\u30aa\u30bf\u30af\u3067\u3059\u3002\u7b11\u3063\u3066\u304f\u3060\u3055\u3044\u3002(\u30de\u30eb\u30c1\u30b3\u30a2\u3067\u306f\u306a\u305c\u304b\u52d5\u304b\u306a\u3044)(\u97f3\u304c\u51fa\u307e\u3059) <a href=\"https:\/\/twitter.com\/hashtag\/Methylenix?src=hash&amp;ref_src=twsrc%5Etfw\">#Methylenix<\/a> <a href=\"https:\/\/twitter.com\/hashtag\/%E8%87%AA%E4%BD%9COS?src=hash&amp;ref_src=twsrc%5Etfw\">#\u81ea\u4f5cOS<\/a> <a href=\"https:\/\/t.co\/AL3F0CNseX\">pic.twitter.com\/AL3F0CNseX<\/a><\/p>&mdash; PG_MANA (@PG_MANA_) <a href=\"https:\/\/twitter.com\/PG_MANA_\/status\/1533812030582292481?ref_src=twsrc%5Etfw\">June 6, 2022<\/a><\/blockquote><script async src=\"https:\/\/platform.twitter.com\/widgets.js\" charset=\"utf-8\"><\/script>\n<\/div><\/figure>\n","protected":false},"excerpt":{"rendered":"<p>\u81ea\u4f5cOS\u3067open\u3068\u304bread\u306eSystemCall\u3092\u5b9f\u88c5\u3057\u3066\u3044\u307e\u3057\u305f\u304c\u3001\u4f55\u304b\u9762\u767d\u3044\u3082\u306e\u3092\u4f5c\u308a\u305f\u304f\u306a\u3063\u305f\u306e\u3067\u3001\u6700\u8fd1\u306e\u81ea\u4f5cOS\u3067\u306f\u4e00\u3064\u306e\u76ee\u6a19(?)\u3068\u3055\u308c\u3066\u3044\u308bWeb\u30b5\u30fc\u30d0\u3092\u52d5\u304b\u3059\u3053\u3068\u3092\u76ee\u6a19\u3068\u3059\u308b\u3053\u3068\u306b\u3057\u307e\u3057\u305f\u3002<br \/>\n\u3068\u308a\u3042\u3048\u305a\u4f7f\u7528\u3059\u308b\u30b7\u30b9\u30c6\u30e0\u30b3\u30fc\u30eb\u3092\u63a2\u308b\u305f\u3081\u306bC\u8a00\u8a9e\u3067\u8d85\u7c21\u6613\u7248\u306eWeb Server\u3092\u66f8\u3044\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-852","post","type-post","status-publish","format-standard","hentry","category-programming"],"_links":{"self":[{"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/posts\/852","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/comments?post=852"}],"version-history":[{"count":0,"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/posts\/852\/revisions"}],"wp:attachment":[{"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/media?parent=852"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/categories?post=852"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pg-mana.net\/blog\/wp-json\/wp\/v2\/tags?post=852"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}