(给DotNet加星标,提升.Net技能)

转自:农码一生cnblogs.com/zhaopei/p/Socket2.html

前言

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

Socket模拟浏览器的Url Get请求

首先浏览器的请求是HTTP协议。我们上一篇《你也可以写个聊天程序 C# Socket学习》说过,HTTP是短连接,用完就断开,是无状态的。所以我们在等待响应的时候不需要另外开个线程循环等待。

也就是我们只需要通过Socket和服务器建立连接,然后发送请求,然后接收服务器的响应,这样就完成了一次请求。

可是,我们一般访问网页的时候都是通过域名,没有IP也没有端口,怎么和服务器建立连接了。这里就需要用到我们上篇介绍的几个类了:

//根据DNS获取域名绑定的IPforeach (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.htmlif (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

推荐阅读

(点击标题可跳转阅读)

ASP.NET Core 3.x 并发限制

.NET Core中的类DispatchProxy实现AOP

三分钟学会Redis在.NET Core中做缓存中间件

看完本文有收获?请转发分享给更多人

关注「DotNet」加星标,提升.Net技能

好文章,我在看❤️

c#字符串按位转成asc_C# 你也可以写个服务器相关推荐

  1. c#字符串按位转成asc_C#中string和ASCII相互转换

    1.字符(串)转为ASCII码: 思路:1)把字符(串)直接转换为int类型,即可得到ASCII码: 2)再将数字转换为字符串转出: 如:单个字符 int asc = (int)'a'; Consol ...

  2. python由列表中提取出来的浮点型字符串不能直接转换成整形

    案例如下: lst = ['636', 'system', '10', '-10', '1.1G', '114M', '95M', 'S', '45.0', '12.9', '1:15.87', 'c ...

  3. 将Macbook的光驱位升级成SSD

    本文章共有四个部分: 1.Macbook Pro情况描述 2.前期准备 3.正式开始更换SSD 4.将系统装在SSD上 5.出现的问题 Macbook Pro情况描述: 我的MBP是12年中的13寸M ...

  4. .NET(C#)时间日期字符串(String)格式化转换成Datetime异常报错问题

    .NET(C#)时间日期字符串(String)格式化转换成Datetime异常报错问题 参考文章: (1).NET(C#)时间日期字符串(String)格式化转换成Datetime异常报错问题 (2) ...

  5. json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值...

    json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值 原文:json字符串转换成json对象,json对象转换成字符串,值转换成字符串,字符串转成值 主要内容: 一 ...

  6. python 如何将字符串数字列表转换成数字列表,如何将数字列表转换成字符串数字列表?map(eval,list(str))

    字符串数字列表转换成数字列表 # -*- encoding: utf-8 -*- """ @File : test.py @Time : 2019/10/28 23:37 ...

  7. java传入一个字符串 将它分割成大写字符为首的字符串数组

    /*      * 传入一个字符串 将它分割成大写字符为首的字符串数组      */     private ArrayList<String> splitByUpperCase(Str ...

  8. 用StringBuilder 或StringBuffer: 把字符串“ABCDE”,转变成字符串“A,B,C,D” (注意,最后一个E是需要删除的)

    用StringBuilder 或StringBuffer: 把字符串"ABCDE",转变成字符串"A,B,C,D" (注意,最后一个E是需要删除的) publi ...

  9. (7)-(Reverse Integer)-(将整数按位反转成另外一个整数,考虑溢出)-(知道最大整数和最小整数值)...

    (7)-(Reverse Integer)-(将整数按位反转成另外一个整数,考虑溢出)-(知道最大整数和最小整数值)//Reverse digits of an integer.//Example1: ...

最新文章

  1. 2021 CSDN年度回忆录
  2. ubuntu18.04下安装tomcat8.5
  3. Makedown 本地图片问题
  4. exp导出excel oracle_如何从Oracle快速导出数据到Excel
  5. 一些Base64编码/解码及数据压缩/解压方面的知识
  6. 莫名其妙就发个手机!这家公司员工晒年终奖品:人手一部iPhone 11
  7. 2021年中国丁香香烟市场趋势报告、技术动态创新及2027年市场预测
  8. [学习官方例子]TCustomComparer
  9. ActiveMQ的消息存储方式
  10. 关于如何让网站被搜索引擎收录
  11. 解答篇:金蝶K3wise总账凭证页面查询不到科目分录核算项目
  12. YIT-CTF—社工类
  13. Redis源码阅读笔记(二)list双向链表结构
  14. 【操作系统】CPU(处理器)调度
  15. 抖音二面:为什么模块循环依赖不会死循环?CommonJS和ES Module的处理不同?
  16. python 京东 抢券_Python写一个京东抢券脚本
  17. 51单片机ROM和RAM
  18. Swift 参数可选和必选的区别
  19. quagga命令行解析
  20. 文学阅读---菜根谭(1)

热门文章

  1. 【AHK】不用切换中英输入法打出英文符号
  2. Egret实战开发笔记,飞行射击游戏(二)
  3. bluebird promise化之循环方法
  4. windows wls
  5. RMAN异机恢复步骤
  6. 【17】SCI易中期刊推荐——计算机信息系统电子与电气(中科院4区)
  7. 最通俗易懂的超级无敌简单的HTML表格添加功能案例
  8. 《港联证券》新三板股票交易规则是什么?如何进行交易?
  9. 社招前端必会手写面试题集锦
  10. 阿里云峰会 | 深化城市计算场景能力,为企业数智化建设提供助推力