LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

C# 如何编写一个web网页服务器

admin
2025年7月8日 12:39 本文热度 54

前言


这里说的服务器是Web服务器,是类似IIS、Tomcat之类的,用来响应浏览器请求的服务。


Socket模拟浏览器的Url Get请求


首先浏览器的请求是HTTP协议。我们上一篇《你也可以写个聊天程序 C# Socket学习》说过,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 = 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 = 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)的时候已经进行了三次握手



具体可细读小坦克大佬(https://www.cnblogs.com/TankXiao/archive/2012/10/10/2711777.html)的文章。


也就是说我们在用C#的Socket、TCP、HttpClient的时候根本就不用关注这些细节。


另外套接字有三种不同的类型:流套接字、数据报套接字和原始套接字。前两者是标准套接字,分别对应TCP和UDP。而原始套接字则更加底层更加牛逼,普通开发人员一般接触不到。


我们说的HTTP、TCP、UDP之类都是网络协议,那协议到底是什么?通俗的说其实只是你我他之间的一个约定而已,大家都按规定了来那就可以说是协议。


而HTTP又是建立在TCP之上的,也就是说基础协议之后再加约定又可以成为一种新的协议。下章我们将用Socket来实现ModbusTCP协议对寄存器读和写。


结束


完整demo

https://github.com/zhaopeiym/BlogDemoCode/tree/master/Socket编程/2HTTP


转自:农码一生

cnblogs.com/zhaopei/p/Socket2.html


该文章在 2025/7/9 9:13:52 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved