BeetleX之简单HTTP/HTTPS实现

        在通讯应用中很多时候需要和已有标准的应用协议进行通讯,针对这情况就要针对相应协议的实现;标准协议上考虑的情况比较多,所以协议的复杂度也相对高些,对比之前的Protobuf通讯的简单协议来说则会复杂。接下来用组件去实现一个简单的HTTP协议服务,让浏览器可以去访问它。

HTTP协议

        对于HTTP协议的介绍相信也不用过多描述,毕竟这个协议已经应用了N年了,网上针对这一协议的介绍也非常多。这协议的版本有1.0,1.1和2.0,接下来实现的是HTTP1.1。其实更符合多场景应用是2.0,不过2.0的协议复杂度就比较高了,所以就不在这里实现介绍了。

        HTTP 1.1协议只允许同一时间处理一个请求,就是当服务端接收到请求后直到响应完成才会处理下一下请求。为了满足这需要针对通讯协议制定了Request和Response对象。

Request对象
        该对象主要用于收集HTTP的请求信息,定义如下:

    class HttpRequest{//当前HTTP版本信息public string HttpVersion { get; set; }//请求的方法public string Method { get; set; }//基础的urlpublic string BaseUrl { get; set; }//客户端IPpublic string ClientIP { get; set; }//请求路径public string Path { get; set; }//Url参数public string QueryString { get; set; }//完整URLpublic string Url { get; set; }//头部信息public Dictionary<string, string> Headers { get; private set; } = new Dictionary<string, string>();//HTTP内容public byte[] Body { get; set; }//HTTP内容长度public int ContentLength { get; set; }//请求对象状态public RequestStatus Status { get; set; } = RequestStatus.None;}

以上是一个HTTP请求的简单描述对象,服务会根据网络数据根据HTTP协议转换成相应的对象消息。

HttpResponse对象

        该对象用于设置请求响应内容,定义如下:

    class HttpResponse : IWriteHandler{public HttpResponse(){Headers["Content-Type"] = "text/html";}public string HttpVersion { get; set; } = "HTTP/1.1";public int Status { get; set; }public string StatusMessage { get; set; } = "OK";public string Body { get; set; }public Dictionary<string, string> Headers = new Dictionary<string, string>();public void Write(Stream stream){var pipeStream = stream.ToPipeStream();//写入响应状态pipeStream.WriteLine($"{HttpVersion} {Status} {StatusMessage}");//写入头部信息foreach (var item in Headers)pipeStream.WriteLine($"{item.Key}: {item.Value}");byte[] bodyData = null;if (!string.IsNullOrEmpty(Body)){bodyData = Encoding.UTF8.GetBytes(Body);}if (bodyData != null){pipeStream.WriteLine($"Content-Length: {bodyData.Length}");}pipeStream.WriteLine("");//写入响应消息体if (bodyData != null){pipeStream.Write(bodyData, 0, bodyData.Length);}Completed?.Invoke(this);}public Action<IWriteHandler> Completed { get; set; }}

对象实现了IWriteHandler接口,用于告诉组件提供自定义流输出实现。

协议实现

        在这个示例中协议分析并没有实现IPacket,而是直接接管SessionReceive方法来对流进行HTTP协议分析,具体实现代码如下:

public override void SessionReceive(IServer server, SessionReceiveEventArgs e)
{var request = GetRequest(e.Session);var pipeStream = e.Stream.ToPipeStream();if (LoadRequest(request, pipeStream) == RequestStatus.Completed){OnCompleted(request, e.Session);}
}private RequestStatus LoadRequest(HttpRequest request, PipeStream stream)
{//分析HTTP请求信息LoadRequestLine(request, stream);//分析头信息LoadRequestHeader(request, stream);//加载BodyLoadRequestBody(request, stream);return request.Status;
}private void LoadRequestLine(HttpRequest request, PipeStream stream)
{if (request.Status == RequestStatus.None){if (stream.TryReadLine(out string line)){var subItem = line.SubLeftWith(' ', out string value);request.Method = value;subItem = subItem.SubLeftWith(' ', out value);request.Url = value;request.HttpVersion = subItem;subItem = request.Url.SubRightWith('?', out value);request.QueryString = value;request.BaseUrl = subItem;request.Path = subItem.SubRightWith('/', out value);if (request.Path != "/")request.Path += "/";request.Status = RequestStatus.LoadingHeader;}}
}private void LoadRequestHeader(HttpRequest request, PipeStream stream)
{if (request.Status == RequestStatus.LoadingHeader){while (stream.TryReadLine(out string line)){if (string.IsNullOrEmpty(line)){if (request.ContentLength == 0){request.Status = RequestStatus.Completed;}else{request.Status = RequestStatus.LoadingBody;}return;}var name = line.SubRightWith(':', out string value);if (String.Compare(name, "Content-Length", true) == 0){request.ContentLength = int.Parse(value);}request.Headers[name] = value.Trim();}}
}
private void LoadRequestBody(HttpRequest request, PipeStream stream)
{if (request.Status == RequestStatus.LoadingBody){if (stream.Length >= request.ContentLength){var data = new byte[request.ContentLength]; ;stream.Read(data, 0, data.Length);request.Body = data;request.Status = RequestStatus.Completed;}}
}

在分析过程中最常用的方法是TryReadLine,主要原因HTTP的头信息数据都是以换行的方式来描述,直到读取一个空行表明头部已结。如果存在Content-Length头信息描述说明存在消息体(HTTP有两种描述消息体的情况,这里就不多作介绍了)。

服务处理

        协议处理好后就可以集成在服务中,相对于协议分析来说集成就更简单了。

public static void Main(string[] args)
{mServer = SocketFactory.CreateTcpServer<Program>();mServer.Options.DefaultListen.Port = 80;mServer.Options.AddListenSSL("ssl.pfx", "123456");mServer.Open();System.Threading.Thread.Sleep(-1);
}
private void OnCompleted(HttpRequest request, ISession session)
{HttpResponse response = new HttpResponse();StringBuilder sb = new StringBuilder();sb.AppendLine("<html>");sb.AppendLine("<body>");sb.AppendLine($"<p>Method:{request.Method}</p>");sb.AppendLine($"<p>Url:{request.Url}</p>");sb.AppendLine($"<p>Path:{request.Path}</p>");sb.AppendLine($"<p>QueryString:{request.QueryString}</p>");sb.AppendLine($"<p>ClientIP:{request.ClientIP}</p>");sb.AppendLine($"<p>Content-Length:{request.ContentLength}</p>");foreach (var item in request.Headers){sb.AppendLine($"<p>{item.Key}:{item.Value}</p>");}sb.AppendLine("</body>");sb.AppendLine("</html>");response.Body = sb.ToString();ClearRequest(session);session.Send(response);
}

在服务中把默认监听的端口改成80,然后添加一个SSL监听用于支持HTTPS访问;示例中通过OnCompleted方法响应请求内容,主要返回的内容是把当前请求的请求详细信息输出。

访问结果

        启动服务后可以通过浏览器访问相关地址:

  • HTTP

  • HTTPS

由于证书是自己创建的,所以会被浏览器标记为不安全。

下载

链接:https://pan.baidu.com/s/1P7QTSjJH4Q1ftHiRoQT8MQ 

提取码:7kig 

【BeetleX通讯框架代码详解】
BeetleX

开源跨平台通讯框架(支持TLS)
轻松实现高性能:tcp、http、websocket、redis、rpc和网关等服务应用

https://beetlex.io

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307442.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

体验.NET5 RC1极致性能,你也要“卧槽”!

“ 9月14日&#xff0c;.NET5发布了(Release Candidate)RC1版本&#xff0c;是11月正式版本之前两个RC版本中第一个&#xff0c;包含语言新版本C#9和F#5&#xff0c;需要用Visual Studio 2019 (v16.8, Preview 3)才能使用&#xff0c;注意不是Visual Studio 2019&#xff0c;二…

leetcod383. 赎金信

一:题目 二:上码 class Solution { public:bool canConstruct(string ransomNote, string magazine) {unordered_map<char,int>m;for (auto ch:ransomNote) {m[ch];}for (auto ch: magazine) {if(m.find(ch) ! m.end() && m[ch] > 0) m[ch]--;//当magazine中的…

马斯克推崇的第一性原理,究竟有多重要?

职场&认知洞察 丨 作者 / findyi这是findyi公众号的第79篇原创文章最近&#xff0c;第一性原理这个原本离大众很远的物理概念&#xff0c;被媒体炒的火热。第一性原理最开始是由亚里士多德提出来的。他认为任何一个系统都有一个「第一性原理」。他说&#xff1a;“在每个系…

Gartner 组织世界BI大会,PowerBI 与 Tableau 同台竞技

日前&#xff0c;Gartner 组织了全球顶级 BI 产品大会&#xff0c;由于疫情影响&#xff0c;只能远程举办。官方网址如下&#xff1a;https://blogs.gartner.com/rita-sallam/2020/09/11/bi-bake-off-goes-virtual/该会议的原文为&#xff1a;BI Bake-Off&#xff0c;含义为&am…

leetcode15. 三数之和(详解)

一:题目 二:上码 class Solution { public:/**思路:1.这个题出其不意之处在于,其先对这个序列进行了排序排序的好处是1>:如果首元素是大于0的,那么如果无论无何也凑不出02>:同时我们也把相同的元素凑成一块了 可以方便去重了2.接下来,我们就是利用双指针 来处理 数据是否…

BeetleX之TCP消息通讯Protobuf/TLS

在网络通讯应用中直接操作数据流是比较繁琐的事情&#xff0c;毕竟在业务层面处理的都是对象化消息&#xff1b;为了让网络数据操作变得更友好直观&#xff0c;一般都会引用序列化组件来处理网络流和对象之前的转换工作&#xff1b;在这里介绍组件如何使能Protobuf进行数据交互…

leetcode18. 四数之和

一:题目 二:上码 class Solution { public:/**思路:1.这个跟三数之和差别在于本题加了一层循环,就是我们将第二层循环加在了我们遍历的第一个元素的后面2.其他跟三数之和解题思路一样*/vector<vector<int>> fourSum(vector<int>& nums, int target) {vec…

面试 .NET 开发​,为什么也要考算法?​

最近有不少人面试&#xff0c;我发现很多候选人&#xff0c;聊起架构、框架侃侃而谈&#xff0c;但一写代码&#xff0c;就暴露真实水平。说白了&#xff0c;还是基本功不够扎实。在我看来&#xff0c;所有基本功中&#xff0c;最核心的一定是数据结构与算法。也因此&#xff0…

leetcode344. 反转字符串

一:题目 二:上码 class Solution { public:/**思路:利用双指针来进行处理*/void reverseString(vector<char>& s) {for (int i 0,j s.size()-1; i < j; i,j--) {swap(s[i],s[j]);}} };

跟我一起学.NetCore之WebApi接口裸奔有风险(Jwt)

前言撸码需谨慎&#xff0c;裸奔有风险。经常在一些技术交流群中了解到&#xff0c;还有很多小伙伴的项目中Api接口没有做任何安全机制验证&#xff0c;直接就裸奔了&#xff0c;对于一些临时项目或是个人小项目还好&#xff0c;其余的话&#xff0c;建议小伙伴们酌情考虑都加上…

leetcode541. 反转字符串 II

一:题目 二:上码 class Solution { public:/**思路:1.这个我们需要利用到一个库函数 reverse(nums.begin(),nums.end()); // 将字符串反转那么将局部字符串的反转reverse(nums.begin(),nums.begin()2);//表示的是下标左闭右开的 [0,2)2.还有就是在处理每隔2*k这个问题上 我们选…

你是个失败者,有什么资格说话?

这是头哥侃码的第219篇原创这次十一长假&#xff0c;想必有不少朋友和我一样&#xff0c;跟家人聚在一起&#xff0c;吃个饭&#xff0c;喝点小酒&#xff0c;或者吃吃甜点&#xff0c;喝喝下午茶&#xff0c;“享受” 着在疫情严峻形式下难得的宁静时光。两天前&#xff0c;为…

leetcode151. 颠倒字符串中的单词(思路+详解)

一:题目 二:上码 class Solution { public:/**思路:1.去空格(字符串首部的空格 字符串中间的空格 字符串尾部的空格)1>:这里的话 我们就用到了双指针去空格 fastindex遇见空格直接跳过当fastindex遇不见空格&#xff0c;就将值赋值给fastindex;2.字符串反转3.将单词反转*/…

Azure 内容审查器之羞羞图审查

上一篇 Azure 内容审查器之文本审查我们已经介绍了如果使用Azure进行文字内容的审核。对于社区内容&#xff0c;上传的图片是否含有羞羞内容也是需要过虑的。但是最为一般开发者自己很难实现这种级别的智能识别。但是借助Azure的内容审查器可以分分钟实现它。创建内容审查器在使…

在springboot项目中 static中的 style.css加载不出来

一:问题展示 二:问题解决 404问题你就记住 绝逼是路径出了问题 我以前的写法 报错 修改之后的&#xff1a;可以正常显示

聊一聊mongodb中的 explain 和 hint

看到explain和hint的时候&#xff0c;第一个想到的就是mysql&#xff0c;确实&#xff0c;这就是在mysql中借鉴过来的&#xff0c;既然是借鉴过来的&#xff0c;我想大家都知道这两个关键字的用处&#xff0c;话不多说&#xff0c;速速观看~~~一&#xff1a;explain演示 1. 构建…

leetcode28. 实现 strStr()

一:题目 二:上码 class Solution { public:/**思路:1.KMP算法,主要处理的是字符串匹配的问题2.这里边需要用到next数组 也就是前缀表;那么我们为什么要用前缀表呢&#xff0c;当我们进行匹配字符的时候发现匹配到不相同的字符的时候,那么我们就需要在匹配字符串中查询前一个字符…

Blazor 火了,不禁让人想起已死的Silverlight !

Blazor 火了&#xff0c;Blazor是.NET on browser在开放标准下的一次全新尝试&#xff0c;也将是C#成为全平台全栈语言的最后一块拼图。技术上基于Xamarin团队正在开发的一套运行在wasm上的CLR实现。目前Blazor最直接的受益者还是那些想要做前端的C#开发者&#xff0c;有熟悉的…

xshell过期怎么办

一&#xff1a;问题展示 二:问题的解决 如果我们是出于学习的目的的话&#xff0c;那么我们就可以下载家庭版学生版的免费版本 下载地址:https://www.xshell.com/zh/free-for-home-school/ 然后就等着人家给你发邮件就行了 发完邮件点击里面的链接

C#刷剑指Offer | 二叉树中和为某一值的路径

【C#刷题】| 作者 / Edison Zhou这是EdisonTalk的第292篇原创内容我们来用之前学到的数据结构知识来刷《剑指Offer》的一些核心题目&#xff08;精选了其中30道题目&#xff09;&#xff0c;希望对你有帮助&#xff01;本文题目为&#xff1a;二叉树中和为某一值的路径。1题目介…