当前位置: 首页 > news >正文

无锡建设局施工许可证网站wordpress标题不能空

无锡建设局施工许可证网站,wordpress标题不能空,网站设计学习,flv网站建设 作者#xff1a;დ旧言~ 座右铭#xff1a;松树千年终是朽#xff0c;槿花一日自为荣。 目标#xff1a;了解什么是HTTP协议。 毒鸡汤#xff1a;有些事情#xff0c;总是不明白#xff0c;所以我不会坚持。早安! 专栏选自#xff1a;网络 作者დ旧言~ 座右铭松树千年终是朽槿花一日自为荣。 目标了解什么是HTTP协议。 毒鸡汤有些事情总是不明白所以我不会坚持。早安! 专栏选自网络 望小伙伴们点赞收藏✨加关注哟 ​​ 一、前言 前面我们已经学习了网络的基础知识对网络的基本框架已有认识算是初步认识到网络了如果上期我们的学习网络是步入基础知识那么这次学习的板块就是基础知识的实践我们今天的板块是学习网络重要之一学习完这个板块对虚幻的网络就不再迷茫 二、主体 学习【网络】应用层——HTTP协议咱们按照下面的图解 2.1 HTTP协议简介 概念 HTTP 协议 是 Hyper Text Transfer Protocol超文本传输协议的缩写是用于从万维网 WWW:World Wide Web 服务器传输超文本到本地浏览器的传送协议。HTTP 是一个基于 TCP/IP 通信协议来传递数据HTML 文件、图片文件、查询结果等。HTTP协议用于在客户端和服务器之间传输超文本。它是 Web 的基础可用于检索和提交信息例如 HTML 文件、图像、样式表等。HTTP 是无状态的也就是说每个请求都是独立的服务器不会存储任何有关先前请求的信息。HTTP协议常用于浏览器与 Web 服务器之间的通信。 2.2 认识URL 概念 在WWW上每一信息资源都有统一的且在网上的地址该地址就叫URLUniform Resource Locator,统一资源定位器它是WWW的统一资源定位标志就是指网络地址。平时我们俗称的 网址 其实就是说的 URLURL标识了Internet上的每一个唯一的网页。 URL组成部分如下 协议方案名 概念 http://表示的是协议名称表示请求时需要使用的协议通常使用的是HTTP协议或者是安全协议HTTPS。 常见的应用层协议 DNSDomain Name System协议域名系统。FTPFile Transfer Protocol协议文件传输协议。TELNETTelnet协议远程终端协议。HTTPHyper Text Transfer Protocol协议超文本传输协议。HTTPSHyper Text Transfer Protocol over SecureSocket Layer协议安全数据传输协议。SMTPSimple Mail Transfer Protocol协议电子邮件传输协议。POP3Post Office Protocol - Version 3协议邮件读取协议。SNMPSimple Network Management Protocol协议简单网络管理协议。TFTPTrivial File Transfer Protocol协议简单文件传输协议。 登录信息 usr:pass 表示的是登录认证信息包括登录用户的用户名和密码不过登录信息一般不显示在URL中绝大部分URL中的这个字段是被省略的因为登录信息可以通过其他方案交给服务器。 服务器地址 说明 www.example.jp表示的是服务器地址也叫做域名比如www.baidu.comwww.jd.com等。 域名可以被解析成IP地址 补充 在这里我们需要知道的是虽然IP地址可以标识公网内的一台主机但是IP地址一般不会直接给用户看到因为用户看到IP地址后并不知道该IP地址的网站是干什么的但是如果使用www.baidu.com或者www.qq.com这种网址的方式访问网站那么用户至少可以知道这两个域名对应的是哪两家公司。 域名和IP地址是等价的我们同样可以使用IP地址来访问网址但是URL呈现出来是给用户看的所以URL中以域名的方式表示服务器的地址。 服务器端口号 解释 80表示的是服务器的端口号HTTP协议和套接字编程都是位于应用层的因此应用层协议同样也需要有明确的端口号。 当然当我们在使用某种协议时该协议就是在为我们提供服务因此一般常用的服务和端口号之间的关系都是一一对应的所以我们在使用某种协议时并不需要明确指定端口号。因此在URL中服务器的端口号一般都是被省略的。 常见协议对应的端口号 HTTP (Hyper Text Transfer Protocol) 端口号80HTTPS (Secure Hyper Text Transfer Protocol) 端口号443FTP (File Transfer Protocol) 端口号21SMTP (Simple Mail Transfer Protocol) 端口号25POP3 (Post Office Protocol version 3) 端口号110IMAP (Internet Message Access Protocol) 端口号143DNS (Domain Name System) 端口号53DHCP (Dynamic Host Configuration Protocol) 端口号67/68Telnet (Terminal Emulation) 端口号23SSH (Secure Shell) 端口号22NTP (Network Time Protocol) 端口号123SNMP (Simple Network Management Protocol) 端口号161/162RDP (Remote Desktop Protocol) 端口号3389SIP (Session Initiation Protocol) 端口号5060/5061ICQ (Internet Control Message Protocol) 端口号7IRC (Internet Relay Chat) 端口号194BitTorrent 端口号6881-6889 带层次的文件路径 /dir/index.htm 表示的是要访问的资源所在的路径访问服务器的目的是获取服务器上的某种资源通过前面的域名和端口号已经能够找到对应的服务器进程了接下来我们需要指明该资源所在的路径。 在URL当中的路径分隔符用 / 表示而不是 \ 证明了大多数的服务器都是部署在Linux下的。 查询字符串 uid1表示的是请求时提供的额外参数这些参数一般都是以键值对的形式通过服务分隔。当然我们使用百度搜索时提供的搜索关键字也在其中。 片段标识符 ch1表示的是片段标识符是对资源的部分补充当我们在看图片的时候URL当中就会出现片段标识符当我们切换到其他图片时这个符号也会发生变化。 2.3 HTTP协议格式 概念 HTTP是基于请求和响应的应用层服务器作为客户端我们可以向服务器发起请求服务器收到这个请求后会对这个请求做数据分析然后构建response完成一次HTTP请求这种基于request和response的工作方式一般被称为cs或者bs模式c表示clients表示serverb表示browser。 2.3.1 HTTP请求协议格式 HTTP请求协议的格式 请求行请求方法 url http版本请求报头请求的属性这些属性都是以key: value的形式按行陈列的。空行遇到空行表示请求报头结束。请求正文请求正文允许为空字符串如果请求正文存在则在请求报头中会有一个Content-Length属性来标识请求正文的长度。 解释说明 前面三部分是一般是HTTP协议自带的是由HTTP协议自行设置的而请求正文一般是用户的相关信息或数据如果用户在请求时没有信息要上传给服务器此时请求正文就为空字符串这里的空行可以将可以将HTTP的报头和有效载荷进行分离。当服务器收到一个HTTP请求时就可以按行进行读取如果读取到空行则说明已经将报头读取完毕了。 2.3.2 HTTP响应协议格式 HTTP响应协议格式如下 状态行http版本 状态码 状态码描述响应报头响应的属性这些属性都是以key: value的形式按行陈列的。空行遇到空行表示响应报头结束。响应正文响应正文允许为空字符串如果响应正文存在则响应报头中会有一个Content-Length属性来标识响应正文的长度。比如服务器返回了一个html页面那么这个html页面的内容就是在响应正文当中的。 2.4 HTTP的方法 HTTP常见的方法如下 GET方法和POST方法 GET方法用于获取某种资源信息POST方法用于将数据上传给服务器 但实际生活中上传数据时也有可能使用GET方法比如百度官网提交数据时实际使用的就是GET方法。 GET方法通过url传参POST方法通过正文传参 因为url的长度是有限的而正文则可以很长所以使用POST方法通过正文传参可以携带更多的数据同时使用POST方法传参更加私密因为POST方法不会将我们所提交的参数回响到url当中。但是两者都不安全想要更加安全只能通过加密来实现。 表单Form  是 HTML 中一种常用的元素它是用来接受用户输入的一种方式。表单包含了各种表单元素如文本框、单选框、复选框、下拉框等用户可以通过这些元素输入信息然后通过表单提交Submit按钮将这些信息发送到后端服务器。 写一个表单index.html get方法 !DOCTYPE html html langen headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title /head bodyform action/a/b/c/index2.html methodgetname:input typetext namenamebrpasswd:input typepassword namepasswdbrinput typesubmit value提交/form--h1这个是我们的首页/h1 /body /html 结果 分析 我们发现 如果我们要提交参数给我们的服务器我们使用get方法的时候url上加上了我们的参数而我们提交的参数是通过url提交的但是此时在我们网页根目录之下不存在这样的路径所以就返回404。 修改后的代码 !DOCTYPE html html langen headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title /head bodyform action/a/b/c/index2.html methodpostname:input typetext namenamebrpasswd:input typepassword namepasswdbrinput typesubmit value提交/form--h1这个是我们的首页/h1 /body /html 结果 2.5 HTTP的状态码 HTTP状态码是用来表示HTTP请求的处理结果的三位数字代码。它们可以分为五大类信息响应1xx、成功响应2xx、重定向3xx、客户端错误4xx和服务端错误5xx。 信息响应1xx 信息响应表示请求已经被接受但处理尚未完成。常见的状态码有 100 Continue服务器已经接收到请求头并且客户端应继续发送请求体。101 Switching Protocols服务器已经理解并同意将请求切换到新的协议。 成功响应2xx  成功响应表示请求已经被成功处理。常见的状态码有 200 OK请求已成功处理返回结果。201 Created请求已被实现而且有一个新的资源被创建。204 No Content服务器成功处理了请求但没有返回任何内容。 重定向3xx  重定向表示请求的资源已经被移动到了一个新的位置客户端需要重新发送请求。常见的状态码有 301 Moved Permanently请求的资源已经被永久移动到新的位置。302 Found请求的资源已经被临时移动到新的位置。303 See Other请求的资源可以通过GET方法访问另一个URI。307 Temporary Redirect与302类似但指定了临时重定向。 客户端错误4xx 客户端错误表示或者客户端发送的请求有问题。常见的状态码有 400 Bad Request服务器无法理解客户端发送的请求。401 Unauthorized请求需要用户验证。403 Forbidden服务器拒绝处理请求可能是因为客户端没有权限。404 Not Found请求的资源不存在。 服务端错误5xx 服务端错误表示服务器在处理请求时发生了错误。常见的状态码有 500 Internal Server Error服务器在处理请求时发生了未知的错误。503 Service Unavailable服务器暂时无法处理请求通常是因为服务器过载或维护。 2.5.1 见一见404状态码代码 首先我们要明白这个404一定是没找到资源才会触发的 err.html文件 !doctype html html langenheadmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title /headbodydivh1404/h1p页面未找到br/pp您请求的页面可能已经被删除、更名或者您输入的网址有误。br请尝试使用以下链接或者自行搜索:brbra hrefhttps://www.baidu.com百度一下/a/p/div /body /html HttpServer.hpp #pragma once#include iostream #include string #include pthread.h #include sys/types.h #include sys/socket.h #include fstream #include sstream #include vector #include Socket.hppusing namespace std;static const uint16_t defaultport 8877; const string wwwroot ./wwwroot; // web 根目录 const string homepath /index.html; const std::string sep \r\n;class HttpRequest { public:// 反序列化函数用于将字符串格式的HTTP请求分解为请求头和请求体void Deserialize(std::string req){// 假设sep是一个成员变量用于分隔请求头和请求体但在此代码段中未定义// 这里应该是用于分割请求头中每一行的分隔符例如\r\n// while循环用于遍历字符串直到找不到分隔符while (true){// 在请求字符串中查找分隔符\r\n的位置size_t pos req.find(sep);// 如果没有找到分隔符\r\n则退出循环if (pos string::npos)break;// 截取从开头到分隔符\r\n之前的字符串作为请求头的一部分string temp req.substr(0, pos);// 如果截取的字符串为空则也退出循环这通常是不必要的因为find不会返回0位置除非是空字符串if (temp.empty())break;// 将截取的字符串添加到请求头向量中req_header.push_back(temp);// 从请求字符串中移除已经处理的部分包括分隔符req.erase(0, pos sep.size());}// 剩下的字符串如果有的话被认为是请求正文text req;}// 解析函数用于解析请求行的第一部分通常是HTTP方法、URL和HTTP版本void Parse(){// 使用stringstream和字符串流输入操作符来解析请求行的第一个元素std::stringstream ss(req_header[0]); // 将第一行交给ss// 将请求行解析为HTTP方法、URL和HTTP版本ss method url http_version; // gei第一个单词会给method第二个会给url第3个会给http_versionfile_pathwwwroot;//./wwwrootif(url/ || url/index.html){file_pathhomepath;// ./wwwroot/index.html}else{file_pathurl;//./wwwroot/url} }// 调试打印函数用于输出请求的所有信息void DebugPrint(){// 遍历请求头并打印每一行for (auto line : req_header){std::cout -------------------------------- std::endl;std::cout line \n\n;}// 打印解析后的HTTP方法、URL和HTTP版本std::cout method: method std::endl;std::cout url: url std::endl;std::cout http_version: http_version std::endl;std::cout file_path: file_path std::endl;// 打印请求正文std::cout text std::endl;}public:std::vectorstd::string req_header; // 用于存储请求头的字符串向量std::string text; // 用于存储请求正文的字符串std::string file_path;//用于存储转换后的文件地址 // 解析请求行之后得到的结果std::string method; // HTTP方法如GET、POSTstd::string url; // 请求的URLstd::string http_version; // HTTP的版本号如HTTP/1.1 };class HttpServer; // 声明class ThreadData // 传给线程的数据 { public:ThreadData(int fd): _sockfd(fd){}public:int _sockfd; };class HttpServer { public:HttpServer(uint16_t port defaultport): _port(port){}bool Start(){_listensockfd.Socket();_listensockfd.Bind(_port);_listensockfd.Listen();for (;;){// 获取用户信息string clientip;uint16_t clientport;// 两个都是输出型参数// 注意Accept成员函数会返回一个新的套接字专门用于发送信息的int sockfd _listensockfd.Accept(clientip, clientport); // 这里获取了客户端IP和端口号if (sockfd 0)continue;std::cout get a new connect, sockfd: sockfd std::endl;// 下面使用多线程来和用户端进行通信pthread_t tid;ThreadData *td new ThreadData(sockfd);pthread_create(tid, nullptr, ThreadRun, td);}return true;}static string ReadHtmlContent(const string htmlpath) // 读html文件将它的内容存到content{// 坑ifstream in(htmlpath);if (!in.is_open())return ;std::cout htmlpath std::endl;string content;string line;while (getline(in, line)){content line;}in.close();return content;}static void HandlerHttp(int sockfd){char buffer[10240];ssize_t n recv(sockfd, buffer, sizeof(buffer) - 1, 0);// 注意这里我们不用read了而是使用recv函数这个和read非常类似第3个参数为0的时候功能和read一模一样if (n 0) // 读取成功{buffer[n] 0;cout buffer std::endl; // 输出HTTP请求// 这里是巨大变化HttpRequest req;req.Deserialize(buffer);req.Parse();req.DebugPrint();// 返回响应的过程,这里需要返回一个HTTP响应协议std::cout req.file_path std::endl;bool oktrue;string text ReadHtmlContent(req.file_path);//HTTP协议有效载荷——这里是一个简单的网页,这个网页放在req.file_pathif(text.empty()){okfalse;std::string err_htmlwwwroot;err_html/err.html;textReadHtmlContent(err_html);//}string response_line;if(ok){ response_lineHTTP/1.0 200 OK\r\n;//HTTP响应协议的第一行的版本号 状态码 状态码描述}else{response_lineHTTP/1.0 404 Not Found\r\n;//HTTP响应协议的第一行的版本号 状态码 状态码描述}string response_header Content-Length: ;//HTTP报头的最后一行需要记录有效载荷的大小response_header to_string(text.size()); // 11response_header \r\n;//结束这一行string block_line \r\n;//这一行是空行用来区分协议报头和有效载荷string response response_line;response response_header;response block_line;response text;//response 最终就是HTTP/1.0 200 OK\r\nContent-Length: 11\r\n\r\nhello worldsend(sockfd, response.c_str(), response.size(), 0);//注意这里不用write了//send前几个参数和write基本一样当send第4个为0的时候功能和write一模一样}close(sockfd);}static void *ThreadRun(void *args){pthread_detach(pthread_self()); // 分离线程ThreadData *td static_castThreadData *(args);HandlerHttp(td-_sockfd); // 执行http的任务delete td;return nullptr;}~HttpServer(){}private:Sock _listensockfd; // 用于监听的uint16_t _port; // 用于发送消息的 }; 结果  2.5.2 见一见3XX状态码代码 这里只需要修改部分代码 class HttpServer { ......static void HandlerHttp(int sockfd){.......response_lineHTTP/1.0 302 Found\r\n;string response_header Content-Length: ;//HTTP报头的最后一行需要记录有效载荷的大小response_header to_string(text.size()); // 11response_header \r\n;//结束这一行response_header Location: https://www.baidu.com;//注意这里string block_line \r\n;//这一行是空行用来区分协议报头和有效载荷string response response_line;response response_header;response block_line;response text;//response 最终就是HTTP/1.0 200 OK\r\nContent-Length: 11\r\n\r\nhello worldsend(sockfd, response.c_str(), response.size(), 0);//注意这里不用write了//send前几个参数和write基本一样当send第4个为0的时候功能和write一模一样....}}; 2.6 HTTP常见的Header Content-Type数据类型text / html 等Content-LengthBody 的长度用于指示客户端应该接收多少字节的响应Host客户端告知服务器所请求的资源是在哪个主机的哪个端口上User-Agent声明用户的操作系统和浏览器版本信息referer当前页面是从哪个页面跳转过来的location搭配 3xx 状态码使用告诉客户端接下来要去哪里访问Cookie用于在客户端存储少量信息通常用于实现会话session的功能 Keep-Alive(长连接) HTTP 的长连接和短连接都是指在 TCP 层面上的连接。HTTP 协议是基于 TCP 协议的每次 HTTP 请求和响应都需要建立和断开 TCP 连接因此在高并发场景下会产生大量的 TCP 连接开销从而影响性能。如果HTTP请求或响应报头当中的Connect字段对应的值是Keep-Alive就代表支持长连接。 短连接 指每次HTTP请求和响应都建立一个新的 TCP 连接并在请求结束后立即关闭连接。这种方式下每次请求都需要重新建立和断开 TCP 连接会增加连接管理的负担和开销。在 HTTP/1.0 中HTTP 默认采用短连接也就是每次请求和响应都建立和断开一次 TCP 连接。 总结 如今的HTTP/1.1是支持长连接的。所谓的长连接就是建立连接后客户端可以不断地向服务器一次写入多个HTTP请求而服务器在上层一次读取这些请求就行了此时一条连接就可以传送大量的请求和响应。 长连接和短连接有优缺点 长连接可以减少 TCP 连接的建立和断开次数降低网络开销但长时间占用连接会增加服务器资源消耗短连接可以保证每个请求的独立性减少因单个请求错误导致的影响但频繁的 TCP 连接建立和断开会影响性能。因此根据具体的应用场景和需求选择长连接或短连接或者结合两者的优点使用 HTTP/2 的多路复用技术。 2.7 Cookie会话和Session会期 HTTP的特征 无状态每个 HTTP 请求都是独立的服务器不会保存任何客户端的请求信息因此 HTTP 被称为无状态协议。为了维护客户端状态通常使用 Cookie 和 Session技术。可扩展HTTP 报头可以通过添加自定义报头实现扩展功能。灵活HTTP 可以传输任何类型的数据如 HTML、图片、音频、视频等。明文传输HTTP 是明文传输的请求和响应中的所有内容都可以被窃听因此使用 HTTPS 进行加密。请求 / 响应模型HTTP 采用客户端-服务器模型客户端发送请求服务器发送响应。无连接HTTP 协议不维护连接连接是 TCP 协议维护的HTTP直接发起请求和响应即可。缓存HTTP 支持缓存可以通过在响应报头中添加缓存信息控制客户端和服务器的缓存机制。 补充说明 虽然在HTTP的特征中有 无状态 的特点但是我们可以发现每次在使用浏览器的时候却不是这样的当我们在使用账号和密码登陆到一个网站的时候无论我们将该网站关闭还是将浏览器关闭当我们再次打开该网站时我们发现我们的账号还是处于登录状态。 但是在实际应用中为了实现用户的登录状态等功能网站会在服务器端保存用户的会话状态并分配给用户一个唯一的 会话标识符Session ID这个会话标识符可以在每次请求时传递给服务器服务器就可以根据这个标识符识别用户从而实现用户状态的保持。 2.7.1 Cookie 概念 Cookie 是一种小的文本信息由服务器发送给客户端的浏览器然后由浏览器存储在用户的计算机上。它主要用于跟踪和维护Web应用程序的状态以便在不同的HTTP请求之间保持用户的特定信息。简单点来说就是HTTP不支持记录用户状态我们需要一种技术来帮我们支持这种技术目前现在已经内置到HTTP协议当中了他就是Cookie。 补充说明 当我们认证通过后在服务端会进行Set-Cookie设置当服务器在对浏览器进行HTTP响应时就会将这个Set-Cookie相应给浏览器浏览器收到响应后自动提取出Set-Cookie的值并将其保存在浏览器的Cookie文件中此时就相当于我们的账号密码等信息保存在了本地浏览器的Cookie文件中。 当我们再次向该网站发起HTTP请求时该请求当中就会自动包含一个Cookie字段Cookie字段中携带的就是我们第一次的认证信息。因此之后对端服务器在进行认证时只需要提取出HTTP请求当中的Cookie字段即可。 Cookie的种类本质上就时浏览器当中的一个小文件文件里记录的是用户的私有信息 文件级的 Cookie 文件是存储在用户计算机上的硬盘上是一种持久性的 Cookie。它们的过期时间可以设置为一段时间也可以永不过期。在访问同一个网站时浏览器会自动发送该网站存储在本地计算机上的 Cookie文件以便在服务器端进行身份验证和授权操作。内存级的 Cookie 文件是存储在内存中的临时 Cookie。当浏览器关闭时它们会自动删除。内存级的 Cookie 可以用于存储一些敏感信息如密码和银行账户信息等以提高安全性。 2.7.2 SessionID 概念 如果我们仅仅使用Cookie是不安全的因为此时Cookie文件当中是我们的私密信息一旦Cookie文件泄露我们的隐私信息也会泄露。所以就引入了SessionID这样的概念。 当我们第一次输入账号密码验证成功后服务端就会生成一个对应的Session ID并将其发送给客户端。之后客户端每次请求都会携带这个 Session ID服务器就可以根据 Session ID 查找对应的会话对象获取用户的相关信息从而实现用户状态的保持。这个Session ID与用户信息是不相关的。同时系统会将所有登录用户的Session ID统一维护起来。 2.8 构建HTTP请求和响应补充代码 2.8.1 见见简单的HTTP请求 概念说明 事实上上面那些http请求报头都是加密过其实显示出来的效果不好。我们可以自己写一个代码来获取HTTP请求首先我们需要使用套接字所以我们需要将我们之前封装好的套接字拿过来。 Socket.hpp #pragma once #include iostream #include string #include unistd.h #include cstring #include sys/types.h #include sys/stat.h #include sys/socket.h #include arpa/inet.h #include netinet/in.h // 定义一些错误代码 enum { SocketErr 2, // 套接字创建错误 BindErr, // 绑定错误 ListenErr, // 监听错误 }; // 监听队列的长度 const int backlog 10; class Sock //服务器专门使用 { public: Sock() : sockfd_(-1) // 初始化时将sockfd_设为-1表示未初始化的套接字 { } ~Sock() { // 析构函数中可以关闭套接字但这里选择不在析构函数中关闭因为有时需要手动管理资源 } // 创建套接字 void Socket() { sockfd_ socket(AF_INET, SOCK_STREAM, 0); if (sockfd_ 0) { printf(socket error, %s: %d, strerror(errno), errno); //错误 exit(SocketErr); // 发生错误时退出程序 } } // 将套接字绑定到指定的端口上 void Bind(uint16_t port) { //让服务器绑定IP地址与端口号struct sockaddr_in local; memset(local, 0, sizeof(local));//清零 local.sin_family AF_INET; // 网络local.sin_port htons(port); // 我设置为默认绑定任意可用IP地址local.sin_addr.s_addr INADDR_ANY; // 监听所有可用的网络接口 if (bind(sockfd_, (struct sockaddr *)local, sizeof(local)) 0) //让自己绑定别人{ printf(bind error, %s: %d, strerror(errno), errno); exit(BindErr); } } // 监听端口上的连接请求 void Listen() { if (listen(sockfd_, backlog) 0) { printf(listen error, %s: %d, strerror(errno), errno); exit(ListenErr); } } // 接受一个连接请求 int Accept(std::string *clientip, uint16_t *clientport) { struct sockaddr_in peer; socklen_t len sizeof(peer); int newfd accept(sockfd_, (struct sockaddr*)peer, len); if(newfd 0) { printf(accept error, %s: %d, strerror(errno), errno); return -1; } char ipstr[64]; inet_ntop(AF_INET, peer.sin_addr, ipstr, sizeof(ipstr)); *clientip ipstr; *clientport ntohs(peer.sin_port); return newfd; // 返回新的套接字文件描述符 } // 连接到指定的IP和端口——客户端才会用的 bool Connect(const std::string ip, const uint16_t port) { struct sockaddr_in peer;//服务器的信息 memset(peer, 0, sizeof(peer)); peer.sin_family AF_INET; peer.sin_port htons(port);inet_pton(AF_INET, ip.c_str(), (peer.sin_addr)); int n connect(sockfd_, (struct sockaddr*)peer, sizeof(peer)); if(n -1) { std::cerr connect to ip : port error std::endl; return false; } return true; } // 关闭套接字 void Close() { close(sockfd_); } // 获取套接字的文件描述符 int Fd() { return sockfd_; } private: int sockfd_; // 套接字文件描述符 }; 我们可以自己来写一个代码来获取到HTTP请求 #pragma once // 防止头文件被重复包含 #include iostream // 引入标准输入输出流库 #include string // 引入字符串库 #include pthread.h // 引入POSIX线程库 #include Socket.hpp // 假设这是一个封装了socket操作的类 using namespace std; // 使用标准命名空间 // 定义默认端口号 static const uint16_t defaultport 8080; // 线程数据结构体用于在线程间传递socket文件描述符 struct ThreadData { int sockfd; // socket文件描述符 }; // HTTP服务器类 class HttpServer { public: // 构造函数初始化服务器监听的端口 HttpServer(uint16_t port defaultport) : _port(port) // 初始化成员变量_port { } // 启动服务器 bool Start() { _listensockfd.Socket(); // 创建socket _listensockfd.Bind(_port); // 绑定socket到指定的端口 _listensockfd.Listen(); // 开始监听端口 for(;;) // 无限循环等待连接 { string clientip; // 用于存储客户端IP地址 uint16_t clientport; // 用于存储客户端端口号 int sockfd _listensockfd.Accept(clientip, clientport); // 接受连接返回新的socket文件描述符 pthread_t tid; // POSIX线程标识符 printf(get a new connect, sockfd: %d\n, sockfd); // 创建线程数据并传递给新线程 ThreadData *td new ThreadData; td-sockfd sockfd; pthread_create(tid, nullptr, ThreadRun, td); // 创建新线程处理客户端请求 } return true; // 注意这里的return实际上永远不会被执行因为for循环是无限的 } // 静态成员函数用于处理客户端请求 static void *ThreadRun(void *args) { pthread_detach(pthread_self()); // 分离线程让线程在结束时自动释放资源 ThreadData *td static_castThreadData *(args); // 将void*类型的参数转换为ThreadData* char buffer[10240]; // 接收数据的缓冲区 ssize_t n recv(td-sockfd, buffer, sizeof(buffer)-1, 0); // 接收客户端发送的数据 if (n 0) // 如果接收到数据 { buffer[n] 0; // 确保字符串以null字符结尾 cout buffer; // 输出HTTP请求 } close(td-sockfd); // 关闭socket连接 delete td; // 释放线程数据占用的内存 return nullptr; // 线程结束 } // 析构函数用于清理资源但在这个例子中没有特别的资源需要清理 ~HttpServer() { } private: Sock _listensockfd; // 监听socket对象 uint16_t _port; // 服务器监听的端口号 }; 然后我们通过主函数给我们的服务器传入端口号就可以正常启动我们的服务器了 #include HttpServer.hpp #include iostream #include memory #include pthread.husing namespace std;int main(int argc, char *argv[]) {if(argc ! 2){exit(1);}uint16_t port std::stoi(argv[1]);std::unique_ptrHttpServer svr(new HttpServer(port));svr-Start();return 0; } 2.8.2 见见简单的HTTP响应 概念 实现一个最简单的HTTP服务器只在网页上输出 hello world只要我们按照HTTP协议的要求构造数据就很容易能做到。 HTTPserver.hpp #pragma once#include iostream #include string #include pthread.h #include sys/types.h #include sys/socket.h #includeSocket.hppusing namespace std;static const uint16_t defaultport 8877;class HttpServer;//声明class ThreadData//传给线程的数据 { public:ThreadData(int fd): _sockfd(fd){}public:int _sockfd; };class HttpServer { public:HttpServer(uint16_t port defaultport): _port(port){}bool Start(){_listensockfd.Socket();_listensockfd.Bind(_port);_listensockfd.Listen();for (;;){//获取用户信息string clientip;uint16_t clientport;//两个都是输出型参数//注意Accept成员函数会返回一个新的套接字专门用于发送信息的int sockfd _listensockfd.Accept(clientip, clientport);//这里获取了客户端IP和端口号if(sockfd 0) continue;std::coutget a new connect, sockfd:sockfdstd::endl;//下面使用多线程来和用户端进行通信pthread_t tid; ThreadData *td new ThreadData(sockfd);pthread_create(tid, nullptr, ThreadRun, td);}return true;}static void HandlerHttp(int sockfd){char buffer[10240];ssize_t n recv(sockfd, buffer, sizeof(buffer) - 1, 0);//注意这里我们不用read了而是使用recv函数这个和read非常类似第3个参数为0的时候功能和read一模一样if (n 0)//读取成功{buffer[n] 0;cout buffer; // 输出HTTP请求// 返回响应的过程,这里需要返回一个HTTP响应协议string text hello world;//HTTP协议有效载荷string response_line HTTP/1.0 200 OK\r\n;//HTTP响应协议的第一行的版本号 状态码 状态码描述string response_header Content-Length: ;//HTTP报头的最后一行需要记录有效载荷的大小response_header to_string(text.size()); // 11response_header \r\n;//结束这一行string block_line \r\n;//这一行是空行用来区分协议报头和有效载荷string response response_line;response response_header;response block_line;response text;//response 最终就是HTTP/1.0 200 OK\r\nContent-Length: 11\r\n\r\nhello worldsend(sockfd, response.c_str(), response.size(), 0);//注意这里不用write了//send前几个参数和write基本一样当send第4个为0的时候功能和write一模一样}close(sockfd);}static void *ThreadRun(void *args){pthread_detach(pthread_self());//分离线程ThreadData *td static_castThreadData *(args);HandlerHttp(td-_sockfd);//执行http的任务delete td;return nullptr;}~HttpServer(){}private:Sock _listensockfd;//用于监听的uint16_t _port;//用于发送消息的 }; HTTPserver.cc #includeHTTPserver.hpp #include iostream #include string #include memoryint main() {unique_ptrHttpServer psvr (new HttpServer());psvr-Start();return 0; } makefile HttpServer : HTTPserver.ccg -o $ $^ -stdc11 -lpthread.PHONY:clean clean:rm -rf HttpServer 2.8.3 完整型代码 我们需要让他可以动态存储我们需要让他可以实现网页的刷新 HttpServer.hpp测试版 #pragma once#include iostream #include string #include pthread.h #include sys/types.h #include sys/socket.h #include fstream #include sstream #include vector #include Socket.hppusing namespace std;static const uint16_t defaultport 8877; const string wwwroot ./wwwroot; // web 根目录 const string homepath /index.html; const std::string sep \r\n;class HttpRequest { public:// 反序列化函数用于将字符串格式的HTTP请求分解为请求头和请求体void Deserialize(std::string req){// 假设sep是一个成员变量用于分隔请求头和请求体但在此代码段中未定义// 这里应该是用于分割请求头中每一行的分隔符例如\r\n// while循环用于遍历字符串直到找不到分隔符while (true){// 在请求字符串中查找分隔符\r\n的位置size_t pos req.find(sep);// 如果没有找到分隔符\r\n则退出循环if (pos string::npos)break;// 截取从开头到分隔符\r\n之前的字符串作为请求头的一部分string temp req.substr(0, pos);// 如果截取的字符串为空则也退出循环这通常是不必要的因为find不会返回0位置除非是空字符串if (temp.empty())break;// 将截取的字符串添加到请求头向量中req_header.push_back(temp);// 从请求字符串中移除已经处理的部分包括分隔符req.erase(0, pos sep.size());}// 剩下的字符串如果有的话被认为是请求正文text req;}// 解析函数用于解析请求行的第一部分通常是HTTP方法、URL和HTTP版本void Parse(){// 使用stringstream和字符串流输入操作符来解析请求行的第一个元素std::stringstream ss(req_header[0]); // 将第一行交给ss// 将请求行解析为HTTP方法、URL和HTTP版本ss method url http_version; // gei第一个单词会给method第二个会给url第3个会给http_versionfile_pathwwwroot;//./wwwrootif(url/ || url/index.html){file_pathhomepath;// ./wwwroot/index.html}else{file_pathurl;//./wwwroot/url} }// 调试打印函数用于输出请求的所有信息void DebugPrint(){// 遍历请求头并打印每一行for (auto line : req_header){std::cout -------------------------------- std::endl;std::cout line \n\n;}// 打印解析后的HTTP方法、URL和HTTP版本std::cout method: method std::endl;std::cout url: url std::endl;std::cout http_version: http_version std::endl;std::cout file_path: file_path std::endl;// 打印请求正文std::cout text std::endl;}public:std::vectorstd::string req_header; // 用于存储请求头的字符串向量std::string text; // 用于存储请求正文的字符串std::string file_path;//用于存储转换后的文件地址 // 解析请求行之后得到的结果std::string method; // HTTP方法如GET、POSTstd::string url; // 请求的URLstd::string http_version; // HTTP的版本号如HTTP/1.1 };class HttpServer; // 声明class ThreadData // 传给线程的数据 { public:ThreadData(int fd): _sockfd(fd){}public:int _sockfd; };class HttpServer { public:HttpServer(uint16_t port defaultport): _port(port){}bool Start(){_listensockfd.Socket();_listensockfd.Bind(_port);_listensockfd.Listen();for (;;){// 获取用户信息string clientip;uint16_t clientport;// 两个都是输出型参数// 注意Accept成员函数会返回一个新的套接字专门用于发送信息的int sockfd _listensockfd.Accept(clientip, clientport); // 这里获取了客户端IP和端口号if (sockfd 0)continue;std::cout get a new connect, sockfd: sockfd std::endl;// 下面使用多线程来和用户端进行通信pthread_t tid;ThreadData *td new ThreadData(sockfd);pthread_create(tid, nullptr, ThreadRun, td);}return true;}static string ReadHtmlContent(const string htmlpath) // 读html文件将它的内容存到content{// 坑ifstream in(htmlpath);if (!in.is_open())return 404;string content;string line;while (getline(in, line)){content line;}in.close();return content;}static void HandlerHttp(int sockfd){char buffer[10240];ssize_t n recv(sockfd, buffer, sizeof(buffer) - 1, 0);// 注意这里我们不用read了而是使用recv函数这个和read非常类似第3个参数为0的时候功能和read一模一样if (n 0) // 读取成功{buffer[n] 0;cout buffer; // 输出HTTP请求// 这里是巨大变化HttpRequest req;req.Deserialize(buffer);req.Parse();req.DebugPrint();// 返回响应的过程,这里需要返回一个HTTP响应协议string text ReadHtmlContent(req.file_path);//HTTP协议有效载荷——这里是一个简单的网页,这个网页放在req.file_pathstring response_line HTTP/1.0 200 OK\r\n;//HTTP响应协议的第一行的版本号 状态码 状态码描述string response_header Content-Length: ;//HTTP报头的最后一行需要记录有效载荷的大小response_header to_string(text.size()); // 11response_header \r\n;//结束这一行string block_line \r\n;//这一行是空行用来区分协议报头和有效载荷string response response_line;response response_header;response block_line;response text;//response 最终就是HTTP/1.0 200 OK\r\nContent-Length: 11\r\n\r\nhello worldsend(sockfd, response.c_str(), response.size(), 0);//注意这里不用write了//send前几个参数和write基本一样当send第4个为0的时候功能和write一模一样}close(sockfd);}static void *ThreadRun(void *args){pthread_detach(pthread_self()); // 分离线程ThreadData *td static_castThreadData *(args);HandlerHttp(td-_sockfd); // 执行http的任务delete td;return nullptr;}~HttpServer(){}private:Sock _listensockfd; // 用于监听的uint16_t _port; // 用于发送消息的 }; index2.html 跳转外部网页版 !DOCTYPE html html langen headmeta charsetUTF-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleDocument/title /head bodyh1这个是我们的尾页/h1a hrefhttps://www.baidu.com/百度官网/a /body /html 三、结束语  今天内容就到这里啦时间过得很快大家沉下心来好好学习会有一定的收获的大家多多坚持嘻嘻成功路上注定孤独因为坚持的人不多。那请大家举起自己的小手给博主一键三连有你们的支持是我最大的动力回见。 ​​
http://www.w-s-a.com/news/535259/

相关文章:

  • 浦口区网站建设售后服务建设一个网站多少钱
  • 做个小网站大概多少钱广州h5网站
  • 360免费建站视频wordpress标签显示图片
  • 创建简易个人网站国外做网站被动收入
  • 轻定制网站建设网页培训哪个机构好
  • 青岛海诚互联做网站好吗计算机软件开发培训机构
  • 德钦网站建设如何在网站上做用工登记
  • 创意品牌网站云服务
  • 个人备案网站可以做商城展示如何制作网页二维码
  • 网站建设php教程视频百度seo 站长工具
  • 外包小程序两个相同的网站对做优化有帮助
  • 网站备案主体修改wordpress 导航图片
  • 怎么建设网站数据库用vs代码做网站
  • 运营企业网站怎么赚钱动漫制作专业概念
  • 宜春网站建设推广网络推广工作好干吗
  • 网站程序0day平顶山市做网站
  • 企业网站名称怎么写哔哩哔哩网页版官网在线观看
  • 直播网站建设书籍阿里巴巴网站建设销售
  • 肇庆企业自助建站系统郴州网站建设解决方案
  • 长沙专业做网站排名游戏开发大亨内购破解版
  • 网站推广适合女生做吗网站如何开启gzip压缩
  • 做外单阿里的网站建站平台那个好
  • 全国性质的网站开发公司关于网站开发的请示
  • 齐齐哈尔住房和城乡建设局网站生物科技公司网站模板
  • 中国建设协会官方网站前端培训的机构
  • 网站建设套餐是什么北京孤儿院做义工网站
  • 网站如何做微信支付链接做暧小视频xo免费网站
  • SEO案例网站建设重庆建站模板平台
  • 上海seo网站推广公司wordpress 小米商城主题
  • 搭建服务器做网站什么网站可以请人做软件