日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

BeetleX之简单HTTP/HTTPS实现

發布時間:2023/12/4 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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

總結

以上是生活随笔為你收集整理的BeetleX之简单HTTP/HTTPS实现的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。