主頁 > .NET開發 > 你也可以寫個服務器 - C# Socket學習2

你也可以寫個服務器 - C# Socket學習2

2020-09-22 09:04:14 .NET開發

續上篇《你也可以寫個聊天程式 - C# Socket學習1》

前言

這里說的服務器是Web服務器,是類似IIS、Tomcat之類的,用來回應瀏覽器請求的服務,

Socket模擬瀏覽器的Url Get請求

首先瀏覽器的請求是HTTP協議,我們上一篇說過,HTTP是短連接,用完就斷開,是無狀態的,所以我們在等待回應的時候不需要另外開個執行緒回圈等待,
也就是我們只需要通過Socket和服務器建立連接,然后發送請求,然后接收服務器的回應,這樣就完成了一次請求,
可是,我們一般訪問網頁的時候都是通過域名,沒有IP也沒有埠,怎么和服務器建立連接了,這里就需要用到我們上篇介紹的幾個類了:

//根據DNS獲取域名系結的IP
foreach (var address in Dns.GetHostEntry("www.baidu.com").AddressList)
{
    Console.WriteLine($"百度IP:{address}");
}

//字串轉IP地址
IPAddress ipAddress = IPAddress.Parse("192.168.1.101");

//通過IP和埠構造IPEndPoint物件,用于遠程連接
//通過IP可以確定一臺電腦,通過埠可以確定電腦上的一個程式
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 80);

對于HTTP沒有顯示埠默認都是80 (為了簡單這里就先不考慮HTTPS了)
知道了IP和埠,連接是可以建立了,為了得到正確的回應,我們應該給服務器發送什么訊息呢?這里就需要用到HTTP協議了,
具體協議這里就不說了,我們先F12看看瀏覽器的請求報文,然后依葫蘆畫瓢試試,以http://fanyi-pro.baidu.com為例,(現在找個非HTTPS的地址也是不容易了)

然后我們代碼實作如下:

void ...()
{
    //得到主機資訊
    IPHostEntry ipInfo = Dns.GetHostEntry(new Uri("http://fanyi-pro.baidu.com").Host);
    //取得IPAddress[]
    IPAddress[] ipAddr = ipInfo.AddressList;
    //得到服務器ip
    IPAddress ip = ipAddr[0];
    //組合遠程終結點
    IPEndPoint ipEndPoint = new IPEndPoint(ip, 80);
    //創建Socket 實體
    Socket socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    //嘗試連接
    socketClient.Connect(ipEndPoint);
    //發送請求
    Send(socketClient);
    //接收服務器的回應 
    Receive(socketClient); 
}

//接收來自服務端的訊息
void Receive(Socket socketClient)
{
    byte[] data = https://www.cnblogs.com/zhaopei/p/new byte[1024 * 1024];
    while (true)
    {
        //讀取客戶端發送過來的資料
        int readLeng = socketClient.Receive(data, 0, data.Length, SocketFlags.None);
        textBox2.AppendText($"{socketClient.RemoteEndPoint}:{Encoding.UTF8.GetString(data, 0, readLeng)}\r\n");
    }
}

//發送訊息到服務端
void Send(Socket socketClient)
{
    //為了方便演示,僅用請求報文的前兩行即可,(切記:需要嚴格按照報文格式,如,最后需要連續兩次換行)
    var msg = $"GET / HTTP/1.1\r\nHost: {new Uri(textBox1.Text).Host}\r\n\r\n";
    socketClient.Send(Encoding.UTF8.GetBytes(msg));
}

整個流程也就是:

  • 1、dns服務把域名決議成ip
  • 2、通過ip和埠和服務器建立連接(三次握手)
  • 3、獲取html檔案
  • 4、根據檔案里面的鏈接(js、css、img)再重復以上程序

【注意】:發送報文的時候需要嚴格按照報文格式,如,最后需要連續兩次換行、行末不能有空格等,

效果圖:

用Socket實作Web服務器

Web服務器的實作和我們上一篇的Socket聊天服務端其實也差不多,
不同之處就在于,決議請求報文,然后按HTTP協議回復標準的回應報文(我這里為了簡單,就沒有按標準的協議來玩,僅僅只是實作了表面的效果)
代碼如下:

void ...()
{
    //1 創建Socket物件
    Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    //2 系結ip和埠
    IPAddress ip = IPAddress.Parse("127.0.0.1");
    IPEndPoint ipEndPoint = new IPEndPoint(ip, 80);
    socketServer.Bind(ipEndPoint);

    //3、開啟偵聽(等待客戶機發出的連接),并設定最大客戶端連接數為10
    socketServer.Listen(10); 
    
    //阻塞等待客戶端連接
    Task.Run(() => { Accept(socketServer); });
}

//4 阻塞等待客戶端連接
private static void Accept(Socket socketServer)
{
    while (true)
    {
        //阻塞等待客戶端連接
        Socket newSocket = socketServer.Accept();
        Task.Run(() => { Receive(newSocket); });
    }
}

//5 讀取客戶端發送過來的報文
private static void Receive(Socket newSocket)
{
    byte[] data = https://www.cnblogs.com/zhaopei/p/new byte[1024 * 1024];
    while (newSocket.Connected)
    {
        //讀取客戶端發送過來的資料
        int readLeng = newSocket.Receive(data, 0, data.Length, SocketFlags.None);
        //讀取客戶端發來的請求報文
        var requst = Encoding.UTF8.GetString(data, 0, readLeng);
        
        //決議請求報文的請求路徑(可以決議請求路徑、請求檔案、檔案型別)
        var requstFile = requst.Split("\r\n")[0].Split(" ")[1];
        //回復客戶端回應報文
        Send(newSocket, requstFile);
    }
}

//6 回復客戶端回應報文
private static void Send(Socket newSocket, string requstFile)
{
    //這里如果請求的根目錄,默認顯示Index.html
    if (requstFile == "/" ) requstFile = "/Index.html";

    var msg = File.ReadAllText(Directory.GetCurrentDirectory() + requstFile);
    //把訊息內容轉成位元組陣列后發送
    newSocket.Send(Encoding.UTF8.GetBytes(msg));
   
    //回復回應后馬上關閉連接
    newSocket.Shutdown(SocketShutdown.Both);
    newSocket.Close();
}

效果如下:


由此我們知道了.net core為什么可以在不需要iis的情況下,一個黑表單就提供了對網址的訪問,其實也就是KestrelServer通過Socket系結并監聽埠提供的服務,
【注意】:我們系結的ip是127.0.0.1socketServer.Bind(ipEndPoint),所以我們測驗的時候只能在瀏覽器輸入127.0.0.1或者localhost,如果想通過內外ip訪問,我們可以系結任意ipIPAddress.Any,如socketServer.Bind(new IPEndPoint(IPAddress.Any, port))

為什么不見三次握手

對于HTTP/TCP可能大家多少都聽過三次握手,可是在我們在用Socket撰寫Web服務器的時候并沒有看到相關的東西啊,這是怎么回事,
因為我們在客戶端執行連接socketClient.Connect(ipEndPoint)的時候已經進行了三次握手

具體可細讀小坦克大佬的文章,
也就是說我們在用C#的Socket、TCP、HttpClient的時候根本就不用關注這些細節,
另外套接字有三種不同的型別:流套接字、資料報套接字和原始套接字,前兩者是標準套接字,分別對應TCP和UDP,而原始套接字則更加底層更加牛逼,普通開發人員一般接觸不到,
我們說的HTTP、TCP、UDP之類都是網路協議,那協議到底是什么?通俗的說其實只是你我他之間的一個約定而已,大家都按規定了來那就可以說是協議,
而HTTP又是建立在TCP之上的,也就是說基礎協議之后再加約定又可以成為一種新的協議,下章我們將用Socket來實作ModbusTCP協議對暫存器讀和寫,

結束

  • 本文已同步至索引目錄:《物聯網基礎組件IoTClient開發系列》
  • 完整demo:https://github.com/zhaopeiym/BlogDemoCode/tree/master/Socket編程/2HTTP
  • 推薦閱讀:https://www.cnblogs.com/TankXiao/archive/2012/10/10/2711777.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/103533.html

標籤:.NET Core

上一篇:C#函式(建構式)的多載

下一篇:ASP.NET Core API總結(一)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more