基于http协议的服务器代码编写(可以访问指定路径的资源版+添加跳转网页功能+临时重定向+加载图片的原理/方法+多线程版),http请求/响应的序列化/反序列化,href介绍
创始人
2025-01-17 12:03:07
0

目录

可以访问指定路径资源的服务端

编写

引入

介绍

代码

Serialization.hpp

404_err.html

示例

增加跳转网页功能

href

介绍 

代码 

root.html

page1.html

page2.html

示例

添加重定向功能

引入

介绍

代码

示例

添加显示图片功能

引入

介绍

代码

http_server.hpp

Serialization.hpp

root_page.html

示例 

修改为多线程版(短连接) 

介绍

代码


可以访问指定路径资源的服务端

编写

引入

如果我们要访问客户端指定路径的资源,就得把请求拆分出来

  • url里记录了要访问资源的路径
  • 拆分的过程其实就是反序列化

介绍

那么问题就变成了 -- 如何序列化/反序列化 

  • 因为我们只用编写服务端(因为客户端有浏览器自动帮我们进行处理),所以只涉及请求的反序列化+响应的序列化
  • 其实响应的序列化我们早就在上一个版本里做过了,我们把它再做个处理并且拆分出来

请求如何序列化(格式化数据 -> 字符串)呢?

  • 把响应报头放在vector
  • 响应正文单独存放在string里
  • 在拼接的时候,使用某个分隔符分开他们(比如http协议里规定的\r\n,当然这个分隔符只适用于报头部分)

响应如何反序列化(字符串-> 格式化数据)呢?

  • 就是把上述过程反过来
  • 找到分隔符,将得到的数据赋值给结构体对应的字段
  • 详细来说就是:
  • 以\r\n为分隔符,找出报头的每一行,将每一行push到容器里,同时删除掉源串里的内容+"/r/n"
  • 如果读到空行(内容为空)时,就已经将报头读完了
  • 然后寻找报头里的content-length字段,找到后拿到正文长度,就可以继续把正文也拆出来了

如何得到我们的目标url呢?

  • 也就是要继续细化
  • url在请求行里,也就是报头的第一行=vector里的第一个元素
  • 把它以空格为分隔符,拆出三大部分,即可得到纯净的url
  • 我们可以手动分割
  • 也可以利用ss流,它默认以空格为分隔符自动分割,只需要用变量给他接着就行(就像水倒出来,用杯子接着它哈哈哈)

得到url后,我们需要将它和我们自定义的web根目录的位置拼接起来

  • 也就是在上一个版本那里介绍的那样,拼接起来得到[要访问的资源在linux中的实际路径]:

但是这里我们要增加一个特殊处理:

  • 当访问根目录时,需要手动让它访问我们设定的首页文件
  • 并且当访问不存在的页面时,需要手动让它访问我们设定好的错误页面

代码

#pragma once  #include  #include  #include  #include   #include "socket.hpp" #include "Serialization.hpp"  static MY_SOCKET my_socket;  #define buff_size 1024 * 30 #define root_path "./root_page" #define def_file "root.html"  class http_server { public:     http_server(const uint16_t port, const std::string &ip = "0.0.0.0")         : port_(port), ip_(ip) {}     ~http_server() {}     void run()     {         init();         while (true)         {             uint16_t client_port;             std::string client_ip;             lg(DEBUG, "accepting ...");             int sockfd = my_socket.Accept(client_ip, client_port);             if (sockfd == -1)             {                 continue;             }             lg(INFO, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, client_ip.c_str(), client_port);              int ret = fork();             if (ret == 0)             {                 my_socket.Close();                 char buffer[buff_size];                 std::string in_buffer;                  while (true)                 {                     memset(buffer, 0, sizeof(buffer));                     int n = read(sockfd, buffer, sizeof(buffer)); //"size"\n"a op b"\n                     if (n > 0)                     {                         buffer[n] = 0;                         lg(INFO, "get request");                         in_buffer += buffer; // 连续读取                         lg(INFO, "%s", in_buffer.c_str());                         request req;                         req.deserialize(in_buffer);                          // 构建访问资源的路径                         std::string def_page = root_path;                         if (req.url_ == "/")                         {                             def_page += "/";                             def_page += def_file;                         }                         else                         {                             def_page += req.url_;                         }                          // 构建响应                         response res;                         res.version_ = "HTTP/1.1";                         std::string text = get_page(def_page);                         if (text.empty())                         {                              res.code_ = 404;                              res.desc_ = "Not Found";                              def_page = root_path;                              def_page += "/";                              def_page += "404_err.html";                               res.text_ = get_page(def_page);                                                         }                         else                         {                             res.code_ = 200;                             res.desc_ = "OK";                             res.text_ = text;                         }                          std::string cl = "Content-Length: ";                         cl += std::to_string((res.text_).size());                         cl += protocol_sep;                         (res.title_).push_back(cl);                          std::string content;                         res.serialize(content);                          write(sockfd, content.c_str(), content.size());                     }                     else if (n == 0)                     {                         lg(INFO, "%s quit", client_ip.c_str());                         break;                     }                     else // 读出错误                     {                         break;                     }                 }                 // lg(INFO, "fork quit");                 exit(0);                 close(sockfd);             }         }     }  private:     void init()     {         signal(SIGPIPE, SIG_IGN);         signal(SIGCHLD, SIG_IGN);          my_socket.Socket();         my_socket.Bind(port_);         my_socket.Listen();         lg(INFO, "server init done");     }     std::string get_page(std::string path)     {         std::ifstream in(path.c_str());         if (!in.is_open())         {             return "";         }         std::string content, tmp;         while (std::getline(in, tmp))         {             content += tmp;         }         return content;     }  private:     uint16_t port_;     std::string ip_; }; 
Serialization.hpp
#pragma once  #include  #include  #include  #include  #include   #define protocol_sep "\r\n" #define blank_sep ' '  class request { public:     request()         : type_(""), url_(""), version_(""), text_("") {}     bool deserialize(std::string &content)     {         std::string tmp;         size_t left = 0;         while (true)         {             size_t pos = content.find(protocol_sep, left);             if (pos == std::string::npos)             {                 return false;             }              tmp = content.substr(left, pos - left); // 左闭右开             left = pos + 2;             if (tmp.empty()) // 读到空行             {                 break;             }             else             {                 title_.push_back(tmp);             }         }          // 细分请求行         std::string request_line = title_[0];         std::stringstream ss(request_line);         ss >> type_ >> url_ >> version_;          // 如果有正文的话         std::string comp = "Content-Length: ";         bool is_find = false;         int size = 0;         for (auto &it : title_)         {             size_t pos = it.find(comp);             if (pos != std::string::npos)             {                 ssize_t right = it.find(protocol_sep);                 std::string s_size = it.substr(pos + comp.size(), right - pos - comp.size());                 size = stoi(s_size);                 is_find = true;                 break;             }         }         if (!is_find)         { // 没有Content-Length字段             content.erase(0, left + 2);         }         else         {             text_ = content.substr(left + 2, size);             content.erase(0, left + 2 + size);         }         return true;     }  public:     std::string type_;     std::string url_;     std::string version_;     std::vector title_;     std::string text_; };  class response { public:     response()         : version_(""), code_(0), desc_(""), text_("") {}     void serialize(std::string &content)     {         // 响应行         std::string header = version_;         header += blank_sep;         header += std::to_string(code_);         header += blank_sep;         header += desc_;         header += protocol_sep;          // 响应报头         std::string attribute;         for (auto &it : title_)         {             attribute += it;             attribute += protocol_sep;         }          content = header + attribute + protocol_sep + text_;     }  public:     std::string version_;     int code_;     std::string desc_;     std::vector title_;     std::string text_; };
404_err.html

这是我上网随便搜的一个(毕竟咱也不是做前端的,没必要自己写)

        404-对不起!您访问的页面不存在                   
404-对不起!您访问的页面不存在

示例

这是我们创建的多个html文件结构:

访问指定资源:

如果访问的资源不存在:

增加跳转网页功能

href

是 HTML 元素中常用的属性,用于指定链接的目标地址

跳转网页时不一定都发送了请求,因为浏览器会缓存一些网页

介绍 

路径可以是绝对路径,也可以是相对路径

  • 所以可以实现跳转外部/内部网页

代码 

root.html
             my title        

hello.

hello..

hello...

hello world!

跳转至第一个页面

page1

跳转至第二个页面

page2

page1.html
             my title        

第一个页面

hello first

跳转至第二个页面

page2

跳转至首页

root

page2.html
             my title        

第二个页面

hello second

跳转至第一个页面

page1

跳转至首页

root

示例

当我们首先访问page2:

点击跳转首页后:

点击跳转page1后:

添加重定向功能

引入

我们在上一篇博客中介绍过重定向的概念 -- 域名介绍,url的介绍+原理+特殊字符的处理,网络行为,http协议请求/响应的格式+结构,状态码介绍,临时/永久重定向,http报头常见字段,fiddler-CSDN博客

介绍

我们这里假定当客户端访问/302时,就触发重定向功能

  • 也就是让响应的状态码为302
  • 浏览器会帮我们根据http协议 -- 当状态码为302时,自动跳转到location字段定义的资源(这里我们设置为百度主页,都行的啦)
  • 因为只是一个测试嘛,起到一个看看重定向效果的作用

代码

只需要修改动态构建响应部分即可:

    void run()     {         init();         while (true)         {             uint16_t client_port;             std::string client_ip;             lg(DEBUG, "accepting ...");             int sockfd = my_socket.Accept(client_ip, client_port);             if (sockfd == -1)             {                 continue;             }             lg(INFO, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, client_ip.c_str(), client_port);              int ret = fork();             if (ret == 0)             {                 my_socket.Close();                 char buffer[buff_size];                 std::string in_buffer;                  while (true)                 {                     memset(buffer, 0, sizeof(buffer));                     int n = read(sockfd, buffer, sizeof(buffer)); //"size"\n"a op b"\n                     if (n > 0)                     {                         bool code_302 = false;                         buffer[n] = 0;                         lg(INFO, "get request");                         in_buffer += buffer; // 连续读取                         lg(INFO, "%s", in_buffer.c_str());                         request req;                         req.deserialize(in_buffer);                          // 构建访问资源的路径                         std::string def_page = root_path;                         if (req.url_ == "/")                         {                             def_page += "/";                             def_page += def_file;                         }                         else if (req.url_ == "/302")                         {                             code_302 = true;                         }                         else                         {                             def_page += req.url_;                         }                          // 构建响应                         response res;                         res.version_ = "HTTP/1.1";                         if (code_302)                         {                             res.code_ = 302;                             res.desc_ = "Found";                              std::string cl = "Location: ";                             cl += "https://www.baidu.com";                             cl += protocol_sep;                             (res.title_).push_back(cl);                         }                         else                         {                             std::string text = get_page(def_page);                             if (text.empty())                             {                                 res.code_ = 404;                                 res.desc_ = "Not Found";                                 def_page = root_path;                                 def_page += "/";                                 def_page += "404_err.html";                                  res.text_ = get_page(def_page);                             }                             else                             {                                 res.code_ = 200;                                 res.desc_ = "OK";                                 res.text_ = text;                             }                              std::string cl = "Content-Length: ";                             cl += std::to_string((res.text_).size());                             cl += protocol_sep;                             (res.title_).push_back(cl);                         }                          std::string content;                         res.serialize(content);                          write(sockfd, content.c_str(), content.size());                     }                     else if (n == 0)                     {                         lg(INFO, "%s quit", client_ip.c_str());                         break;                     }                     else // 读出错误                     {                         break;                     }                 }                 // lg(INFO, "fork quit");                 exit(0);                 close(sockfd);             }         }     }

示例

服务端收到的请求:

 成功跳转到我们设定好的百度主页

  • 有时候可能会一直转圈圈,多切换下网络

添加显示图片功能

引入

网页一般都会有图片

  • 图片也属于网络资源,也需要浏览器向服务器请求这个资源
  • 所以图片资源也会放在web根目录下

这也就意味着:

  • 当我们请求一个页面后,浏览器不仅需要请求网页,还需要根据页面标签定义的图片资源挨个请求

这也就是为什么新版本的http要支持长连接:

  • 如果还采用短连接,一个连接=一个资源,那万一网页有几百张图片资源,那不得连接死

介绍

插入图片资源的html语法: -- HTML 图像

图片资源其实就是二进制文件,它需要被上层以某种格式解释,才能呈现出我们想要看到的样子

  • 所以就需要添加conten-type字段,来指定该资源的类型
  • 我们之前都没有使用过这个字段,所以他默认以html格式解释
  • 如果是图片的话,就得是image/jpeg / image/png

但是,那么多资源,如何识别哪个资源是那个类型呢?

  • 我们就需要继续细分url了
  • url不是记录了客户端要访问的资源路径吗,就肯定会带上资源的文件名
  • 如果文件名带有.jpg / .png后缀,则为图片资源
  • 如果带有.html后缀,则是我们普通的网页资源
  • 如果是其他的,就默认以html格式解释(这里就简单一点处理啦)

那么,有了后缀,我们还需要将后缀与对应的conten-type的填充值相关联

  • 所以我们需要定义一个键值对容器

既然图片是二进制,那如果还使用[读取文本文件的一行一行读]的方式就不行了

  • 需要增加一个读取二进制的函数,用来区分两者

代码

除了增加了读取图片资源的功能,我还把代码结构修改了很多

http_server.hpp
#pragma once  #include  #include  #include  #include  #include   #include "socket.hpp" #include "Serialization.hpp"  static MY_SOCKET my_socket;  #define buff_size 1024 * 30  class http_server { public:     http_server(const uint16_t port, const std::string &ip = "0.0.0.0")         : port_(port), ip_(ip)     {         content_type_[".html"] = "text/html";         content_type_[".png"] = "image/png";         content_type_[".jpg"] = "image/jpeg";         content_type_[".jpeg"] = "image/jpeg";     }     ~http_server() {}     void run()     {         init();         while (true)         {             uint16_t client_port;             std::string client_ip;             lg(DEBUG, "accepting ...");             int sockfd = my_socket.Accept(client_ip, client_port);             if (sockfd == -1)             {                 continue;             }             lg(INFO, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, client_ip.c_str(), client_port);              int ret = fork();             if (ret == 0)             {                 my_socket.Close();                 char buffer[buff_size];                 std::string in_buffer;                  while (true)                 {                     memset(buffer, 0, sizeof(buffer));                     int n = read(sockfd, buffer, sizeof(buffer)); //"size"\n"a op b"\n                     if (n > 0)                     {                         buffer[n] = 0;                         in_buffer += buffer; // 连续读取                         lg(INFO, "get request: \n%s", in_buffer.c_str());                          // 构建请求                         request req;                         req.deserialize(in_buffer);                          //lg(DEBUG, "path: %s ,url: %s ", (req.path_).c_str(), (req.url_).c_str());                          // 构建响应                         response res;                         handle_response(res, req);                          // 响应序列化                         std::string content;                         res.serialize(content);                          write(sockfd, content.c_str(), content.size());                     }                     else if (n == 0)                     {                         lg(INFO, "%s quit", client_ip.c_str());                         break;                     }                     else // 读出错误                     {                         break;                     }                 }                 exit(0);                 close(sockfd);             }         }     }  private:     void init()     {         signal(SIGPIPE, SIG_IGN);         signal(SIGCHLD, SIG_IGN);          my_socket.Socket();         my_socket.Bind(port_);         my_socket.Listen();         lg(INFO, "server init done");     }     void handle_response(response &res, request &req)     {         int code = req.code_;         std::string path = req.path_;         std::string content_type_data = content_type_[req.suffix_];         //lg(DEBUG, "content_type_data: %s", content_type_data.c_str());          res.version_ = "HTTP/1.1";         if (code == 302)         {             res.code_ = 302;             res.desc_ = "Found";              std::string cl = "Location: ";             cl += "https://www.qq.com";             (res.title_).push_back(cl);             return ;         }          if (code == 404)         {             res.code_ = 404;             res.desc_ = "Not Found";         }         else         {             res.code_ = 200;             res.desc_ = "OK";         }          // 将读取网页和图片资源的方式分开         if (req.suffix_ == ".html")         {             res.text_ = get_page(path);             //lg(DEBUG, "text: %s", (res.text_).c_str());         }         else         {             res.text_ = b_get_page(path);         }          //  构建响应报头         std::string cl = "Content-Length: ";         cl += std::to_string((res.text_).size());         //lg(DEBUG, "text_size: %d", (res.text_).size());         (res.title_).push_back(cl);          cl = "Content-Type: ";         cl += content_type_data;         (res.title_).push_back(cl);     }  private:     uint16_t port_;     std::string ip_;      std::unordered_map content_type_; }; 
Serialization.hpp
#pragma once  #include  #include  #include  #include  #include   #define protocol_sep "\r\n" #define blank_sep ' ' #define root_path "./root_page" #define def_file "root.html"  std::string get_page(std::string path) {     std::string content, tmp;     std::ifstream in(path.c_str());     if (!in.is_open())     {         return "";     }     while (std::getline(in, tmp))     {         content += tmp;     }     in.close();     // printf("content : %s", content.c_str());     return content; } std::string b_get_page(std::string path) {     std::ifstream in(path.c_str(), std::ios_base::binary);     if (!in.is_open())     {         return "";     }     in.seekg(0, std::ios_base::end);     auto len = in.tellg();     in.seekg(0, std::ios_base::beg);      std::string content;     content.resize(len);      in.read((char *)content.c_str(), content.size());     in.close();      return content; }  class request { public:     request()         : type_(""), url_(""), version_(""), text_(""), path_(""), code_(0), suffix_("") {}     bool deserialize(std::string &content)     {         std::string tmp;         size_t left = 0;         while (true)         {             size_t pos = content.find(protocol_sep, left);             if (pos == std::string::npos)             {                 return false;             }              tmp = content.substr(left, pos - left); // 左闭右开             left = pos + 2;             if (tmp.empty()) // 读到空行             {                 break;             }             else             {                 title_.push_back(tmp);             }         }          // 判断是否有正文         std::string comp = "Content-Length: ";         bool is_find = false;         int size = 0;         for (auto &it : title_)         {             size_t pos = it.find(comp);             if (pos != std::string::npos)             {                 ssize_t right = it.find(protocol_sep);                 std::string s_size = it.substr(pos + comp.size(), right - pos - comp.size());                 size = stoi(s_size);                 is_find = true;                 break;             }         }         if (!is_find)         { // 没有Content-Length字段             content.erase(0, left + 2);         }         else         {             text_ = content.substr(left + 2, size);             content.erase(0, left + 2 + size);         }          handle_path();          return true;     }  private:     void handle_path() // 构建访问资源的路径     {         // 细分请求行         std::string request_line = title_[0];         std::stringstream ss(request_line);         ss >> type_ >> url_ >> version_;          // 构建路径         path_ = root_path;         if (url_ == "/")         {             path_ += "/";             path_ += def_file;         }         else if (url_ == "/302")         {             code_ = 302; // 这里设置为重定向到百度页面,所以不能走本地读取             return;         }         else         {             path_ += url_;         }          // 判断该资源是否存在         if (get_page(path_).empty())         {             code_ = 404; // 需要告诉响应,这里发生了404错误             path_ = root_path;             path_ += "/";             path_ += "404_err.html";         }          // 拿到资源后缀         size_t pos = path_.rfind(".");         if (pos == std::string::npos)         {             suffix_ = ".html";         }         else         {             suffix_ = path_.substr(pos);         }     }  public:     std::string type_;     std::string url_;     std::string path_;     int code_;     std::string suffix_;     std::string version_;     std::vector title_;     std::string text_; };  class response { public:     response()         : version_(""), code_(0), desc_(""), text_("") {}     void serialize(std::string &content)     {         // 响应行         std::string header = version_;         header += blank_sep;         header += std::to_string(code_);         header += blank_sep;         header += desc_;         header += protocol_sep;          // 响应报头         std::string attribute;         for (auto &it : title_)         {             attribute += it;             attribute += protocol_sep;         }          content = header + attribute + protocol_sep + text_;     }  public:     std::string version_;     int code_;     std::string desc_;     std::vector title_;     std::string text_; };
root_page.html
             my title        

hello.

hello..

hello...

hello world!

name:
password:

跳转至第一个页面

page1

跳转至第二个页面

page2

示例 

当我们在首页放上我们的图片资源时

  • 访问首页后,浏览器就会根据页面上的html标签继续申请其他资源
  • 这是网页的样式(可以看到图片成功被加载出来了):

修改为多线程版(短连接) 

介绍

服务器收到一个连接后,就创建一个线程去处理请求

  • 并且添加了重连功能

注意:

  • 我们这里是短连接版本,一次连接=处理一次请求
  • 但即使是短连接,也得保证读取到的数据是一份完整的请求
  • 所以我在线程外部定义了一个缓冲区,用于保存处理过程中剩下的数据(因为它有可能是其他连接的一部分)
  • 而线程内部在反序列化时,将完整请求从缓冲区中剥离

代码

#pragma once  #include  #include  #include  #include  #include  #include   #include "socket.hpp" #include "Serialization.hpp"  static MY_SOCKET my_socket;  #define buff_size 1024 * 30  class http_server; struct thread_data {     int sockfd_;     std::string ip_;     std::string &in_buffer_;     http_server *this_; };  class http_server { public:     http_server(const uint16_t port, const std::string &ip = "0.0.0.0")         : port_(port), ip_(ip)     {         content_type_[".html"] = "text/html";         content_type_[".png"] = "image/png";         content_type_[".jpg"] = "image/jpeg";         content_type_[".jpeg"] = "image/jpeg";     }     ~http_server() {}     void run()     {         init();         while (true)         {             uint16_t client_port;             std::string client_ip;              // 一个线程处理一次请求(短连接)             pthread_t pid;             std::string in_buffer;              int sockfd = 0;             int count = 5;             do             {                 lg(DEBUG, "accepting ...");                 sockfd = my_socket.Accept(client_ip, client_port);                 if (sockfd != -1 || --count == 0)                 {                     break;                 }             } while (true);             if (sockfd == -1)             {                 lg(ERROR, "accepting error");             }              lg(INFO, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, client_ip.c_str(), client_port);              thread_data *td = new thread_data{sockfd, client_ip, in_buffer, this};             lg(DEBUG, "create pthread");             pthread_create(&pid, nullptr, entry, reinterpret_cast(td));              // 一个进程服务一个客户端              // lg(DEBUG, "accepting ...");             // int sockfd = my_socket.Accept(client_ip, client_port);             // if (sockfd == -1)             // {             //     continue;             // }             // lg(INFO, "get a new link..., sockfd: %d, client ip: %s, client port: %d", sockfd, client_ip.c_str(), client_port);             //  int ret = fork();             //  if (ret == 0)             //  {             //      my_socket.Close();             //  char buffer[buff_size];             //  std::string in_buffer;              // while (true)             // {             //     memset(buffer, 0, sizeof(buffer));             //     int n = read(sockfd, buffer, sizeof(buffer)); //"size"\n"a op b"\n             //     if (n > 0)             //     {             //         buffer[n] = 0;             //         in_buffer += buffer; // 连续读取             //         lg(INFO, "get request: \n%s", in_buffer.c_str());              //         // 构建请求             //         request req;             //         req.deserialize(in_buffer);              //         // lg(DEBUG, "path: %s ,url: %s ", (req.path_).c_str(), (req.url_).c_str());              //         // 构建响应             //         response res;             //         handle_response(res, req);              //         // 响应序列化             //         std::string content;             //         res.serialize(content);              //         write(sockfd, content.c_str(), content.size());             //     }             //     else if (n == 0)             //     {             //         lg(INFO, "%s quit", client_ip.c_str());             //         break;             //     }             //     else // 读出错误             //     {             //         break;             //     }             // }             //     exit(0);             //     close(sockfd);             // }         }     }  private:     void init()     {         signal(SIGPIPE, SIG_IGN);         signal(SIGCHLD, SIG_IGN);          my_socket.Socket();         my_socket.Bind(port_);         my_socket.Listen();         lg(INFO, "server init done");     }     void handle_response(response &res, request &req)     {         int code = req.code_;         std::string path = req.path_;         std::string content_type_data = content_type_[req.suffix_];         // lg(DEBUG, "content_type_data: %s", content_type_data.c_str());          res.version_ = "HTTP/1.1";         if (code == 302)         {             res.code_ = 302;             res.desc_ = "Found";              std::string cl = "Location: ";             cl += "https://www.qq.com";             (res.title_).push_back(cl);             return;         }          if (code == 404)         {             res.code_ = 404;             res.desc_ = "Not Found";         }         else         {             res.code_ = 200;             res.desc_ = "OK";         }          // 将读取网页和图片资源的方式分开         if (req.suffix_ == ".html")         {             res.text_ = get_page(path);             // lg(DEBUG, "text: %s", (res.text_).c_str());         }         else         {             res.text_ = b_get_page(path);         }          //  构建响应报头         std::string cl = "Content-Length: ";         cl += std::to_string((res.text_).size());         // lg(DEBUG, "text_size: %d", (res.text_).size());         (res.title_).push_back(cl);          cl = "Content-Type: ";         cl += content_type_data;         (res.title_).push_back(cl);     }     static void *entry(void *args)     {         pthread_detach(pthread_self());          thread_data *td = reinterpret_cast(args);         int sockfd = td->sockfd_;         std::string ip = td->ip_;         std::string in_buffer = td->in_buffer_;         http_server *it = td->this_;          // 读取请求         char buffer[buff_size];         bool flag = true;         request req;         while (true) // 虽说是短连接,但也得确保读出来的内容是一个完整的请求         {             memset(buffer, 0, sizeof(buffer));             int n = read(sockfd, buffer, sizeof(buffer));             if (n > 0)             {                 buffer[n] = 0;                 in_buffer += buffer; // 连续读取                 lg(INFO, "get request: \n%s", in_buffer.c_str());                  // 构建请求                 flag = req.deserialize(in_buffer);                 if (flag == false)                 {                     continue;                 }                 else                 {                     break;                 }             }             else if (n == 0)             {                 lg(INFO, "%s quit", ip.c_str());                 return nullptr;             }             else             {                 lg(ERROR, "%s read error", ip.c_str());                 return nullptr;             }         }          // lg(DEBUG, "path: %s ,url: %s ", (req.path_).c_str(), (req.url_).c_str());          // 构建响应         response res;         it->handle_response(res, req);          // 响应序列化         std::string content;         res.serialize(content);          write(sockfd, content.c_str(), content.size());          //  销毁资源         delete td;         close(sockfd);          return nullptr;     }  private:     uint16_t port_;     std::string ip_;      std::unordered_map content_type_; }; 

相关内容

热门资讯

透视私人局(AAPOKEr)a... 透视私人局(AAPOKEr)aa扑克辅助(透视)总是有挂(详细辅助靠谱教程);1、aa扑克辅助系统规...
透视攻略!德州之星有辅助挂,(... 透视攻略!德州之星有辅助挂,(德州nzt)原来是真的有挂(详细辅助2025版教程);1、德州之星有辅...
透视软件(Wpk)wpk发牌逻... 透视软件(Wpk)wpk发牌逻辑(透视)详细辅助专业教程(一直真的是有挂);1、超多福利:超高返利,...
透视数据(aa扑克)aapok... 透视数据(aa扑克)aapoker猫腻(透视)一直存在有挂(详细辅助安装教程);1、aapoker猫...
透视app!德州之星有辅助挂,... 透视app!德州之星有辅助挂,(德扑)都是真的有挂(详细辅助解密教程)1、德州之星有辅助挂ai机器人...
透视有挂(WPK)微扑克辅助软... 透视有挂(WPK)微扑克辅助软件(透视)详细辅助辅助教程(一贯真的是有挂)1、首先打开微扑克辅助软件...
透视实锤(aAPOKER)aa... 透视实锤(aAPOKER)aapoker辅助(透视)其实有挂(详细辅助力荐教程);1、这是跨平台的a...
透视黑科技(Wpk)wpk透视... 透视黑科技(Wpk)wpk透视辅助工具(透视)详细辅助科技教程(一直存在有挂);1、wpk透视辅助工...
透视了解!德州之星辅助,(德州... 透视了解!德州之星辅助,(德州nzt)确实存在有挂(详细辅助详细教程)1、点击下载安装,德州之星辅助...
透视有挂(AApOKER)aa... 透视有挂(AApOKER)aapoker外挂(透视)都是有挂(详细辅助可靠技巧)进入游戏-大厅左侧-...