【C#网络编程系列】专题三:自定义web服务器

本文通过Socket编程和TcpListener两种方式实现了一个简单的Web服务器,介绍了网络端口号、端点等概念,并展示了如何处理HTTP请求及响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 前言:

经过前面的专题中对网络层协议和HTTP协议的简单介绍相信大家对网络中的协议有了大致的了解的, 本专题将针对HTTP协议定义一个Web服务器,我们平常浏览网页通过在浏览器中输入一个网址就可以看到我们想要的网页,这个过程中浏览器只是一个客户端,浏览器(应用层应用程序)通过HTTP协议把用户请求发送到服务端, 服务器接受到发送来的HTTP请求,然后对请求进行处理和响应,最后把响应的内容发送给客户端(浏览器这里充当了用户代理的客户端),浏览器再对接受到的响应内容(一般是HTML文件)进行解释并且显示出来。这就是一次完整的用户请求/响应模型,本专题所讲述的是一个简单的Web服务器,其他一些大型的Web服务器(IIS,Apache)也是这样的一个原理, 本专题只是简单讲述Web服务器的实现原理。

一、Socket编程实现一个简单的Web服务器

      Socket这个概念是在Unix系统中提出来的。在Unix的时代,为了解决传输层的编程问题,Unix提供了类似于文件操作的网络操作方式——Socket,通过Socket,我们就可以像操作文件一样通过打开、写入、读取、关闭等操作完成网络编程,这样就使得网络编程可以统一到文件操作方面,这样就使我们更容易地编写网络应用程序。需要注意的是,应用层的协议需要网络程序专门处理,Socket不负责应用层协议,仅仅负责传输层的协议。

现在介绍下网络端口号(port)的概念,在同一个网络地址中,为了区分使用相同协议的不同应用程序,为不同的应用程序分配一个数字编号,我们把这个编号就成为网络端口号(就是区分同一个网络地址中不同的进程)。端口号是由一个两个字节的整数,所以取值范围为0~65535,这些端口号又分为三类:

  1. 第一类的范围是0~1023,称为众所周知的端口,这些端口号由特定的网络程序使用,例如,TCP协议使用80端口来完成Http协议的传输。
  2. 第二类的范围是1024~49151,称为登记端口,一般情况下不应该在程序中使用。
  3. 第三类的范围是49152~65535,称为私有端口, 这些端口可以由普通用户程序使用。

在我们用Socket开发网络应用程序中,还有一个就是端点的概念,在网络中,通过IP地址,协议和端口号可以唯一地确定网络上的一个应用程序,其中把IP地址和端口的组合叫做端点(EndPoint)。每个Socket需要绑定到一个端点上与其他端点进行通信。

介绍完基本的一些概念后,下面演示通过Socket编程实现一个简单的Web服务器,此实例中就是简单向浏览器返回一个固定的静态页面,实现代码如下:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace MyServer
{
    /// <summary>
    /// 实现一个简单的web服务器,可以向浏览器返回一个静态的HTML页面
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            //获取本机的IP地址
            IPAddress localAddress = IPAddress.Loopback;
            //创建可以访问的端点,41955表示端口号,如果这里设置为0,表示使用一个由系统分配的空闲的端口号
            IPEndPoint endPoint = new IPEndPoint(localAddress, 41955);
            //创建Socket对象,使用IPv4地址,数据通信类型为数据流,传输控制协议TCP协议.
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //将socket绑定到端点上
            socket.Bind(endPoint);
            //设置连接队列的长度
            socket.Listen(10);

            while (true)
            {
                Console.WriteLine("等待一个连接请求....");
                //开始监听,这个方法会堵塞线程的执行,直到接受到一个客户端的连接请求
                Socket clientSocket = socket.Accept();
                //输出客户端的地址
                Console.WriteLine("客户端的地址是:{0}", clientSocket.RemoteEndPoint);
                //把客户端的请求数据读入保存到一个数组中
                byte[] buffer = new byte[2048];
                int receiveLength = clientSocket.Receive(buffer, 2048, SocketFlags.None);
                string requestString = Encoding.UTF8.GetString(buffer, 0, receiveLength);
                //在服务器端输出请求的消息
                Console.WriteLine(requestString);

                //服务器端做出响应
                string stateLine = "Http/1.1/ 200 OK\r\n";
                string responseBody = "<html><head><title>Default Page</title></head><body><p tyle='font:bold;font-size:24pt'>Welcome you</p></body></html>";
                string responseHead = string.Format("Content-Type: text/html; charset=UTf-8\r\nContent-Length: {0}\r\n", responseBody.Length);
                byte[] responseStateLineBytes = Encoding.UTF8.GetBytes(stateLine);
                byte[] responseHeadBytes = Encoding.UTF8.GetBytes(responseHead);
                byte[] responseBodyBytes = Encoding.UTF8.GetBytes(responseBody);
                //向客户端发送信息
                clientSocket.Send(responseStateLineBytes);//状态行
                clientSocket.Send(responseHeadBytes);//头信息
                //发送头部和内容的空行
                clientSocket.Send(new byte[] { 13, 10 });
                clientSocket.Send(responseBodyBytes);//消息体

                //断开连接
                clientSocket.Close();
                Console.ReadKey();
                break;
            }
            //关闭服务器
            socket.Close();
        }
    }
}

运行结果:

首先运行服务端后的界面:


在浏览器中输入http://localhost:41955/ 则浏览器可以看到如下的所示的结果:


      这里只是简单实现了一个web服务器的功能,当然实际的Web服务器通过用户的发来的Http请求中获得请求文件类型,请求文件名以及请求目录等信息,然后Web服务器根据这些请求信息从服务器的物理目录中寻找请求的文件,如果在服务器中找到请求的文件,然后服务器把响应内容发送给客户端。这里只是通过这个简单的Web服务器让大家理解请求/响应模型以及Web服务器的工作原理,一些复杂的Web服务器也是在此基础进行一些其他功能的扩展。

二、基于TcpListener的Web服务器

      在.net平台下, 为了简化网络编程,.net对套接字又进行了一次封装,封装后的类是在System.Net.Sockets命名空间下的TcpListener类和TcpClient类,使用TcpListener类用来监听和接收传入的连接请求,在该类的构造函数中只需要传递一组网络端点信息就可以准备好监听参数,而不需要设置使用的网络协议等细节,调用Start方法后,监听工作就开始(间接调用了Socket.Listen方法),AcceptTcpClient方法将阻塞进程,直到一个客户端发来连接请求为止,这个方法返回一个封装了Socket的TcpClient对象,同时从传入的连接队列中删除该客户端的连接请求。此时通过这个TcpClient对象与客户端进行通信。

下面是基于TcpListener和TcpClient的一个简单的Web服务器的代码:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace TcpWebserver
{
    class Program
    {
        static void Main(string[] args)
        {
            // 获得本机的Ip地址,即127.0.0.1
            IPAddress localaddress =IPAddress.Loopback;
            
            // 创建可以访问的断点,49155表示端口号,如果这里设置为0,表示使用一个由系统分配的空闲的端口号
            IPEndPoint endpoint = new IPEndPoint(localaddress, 49155);

            // 创建Tcp 监听器
            TcpListener tcpListener = new TcpListener(endpoint);
            
            // 启动监听
            tcpListener.Start();
            Console.WriteLine("Wait an connect Request...");
            while (true)
            {
                // 等待客户连接
                TcpClient client =tcpListener.AcceptTcpClient();
                if (client.Connected == true)
                {
                    // 输出已经建立连接
                    Console.WriteLine("Created connection");
                }

                // 获得一个网络流对象
                // 该网络流对象封装了Socket的输入和输出操作
                // 此时通过对网络流对象进行写入来返回响应消息
                // 通过对网络流对象进行读取来获得请求消息
                NetworkStream netstream = client.GetStream();
                // 把客户端的请求数据读入保存到一个数组中
                byte[] buffer = new byte[2048];

                int receivelength = netstream.Read(buffer, 0, 2048);
                string requeststring = Encoding.UTF8.GetString(buffer, 0, receivelength);

                // 在服务器端输出请求的消息
                Console.WriteLine(requeststring);

                // 服务器端做出相应内容
                // 响应的状态行
                string statusLine = "HTTP/1.1 200 OK\r\n";
                byte[] responseStatusLineBytes = Encoding.UTF8.GetBytes(statusLine);
                string responseBody = "<html><head><title>Default Page</title></head><body><p style='font:bold;font-size:24pt'>Welcome you</p></body></html>";
                string responseHeader =
                    string.Format(
                        "Content-Type: text/html; charset=UTf-8\r\nContent-Length: {0}\r\n", responseBody.Length);

                byte[] responseHeaderBytes = Encoding.UTF8.GetBytes(responseHeader);
                byte[] responseBodyBytes = Encoding.UTF8.GetBytes(responseBody);
                
                // 写入状态行信息
                netstream.Write(responseStatusLineBytes, 0, responseStatusLineBytes.Length);
                // 写入回应的头部
                netstream.Write(responseHeaderBytes, 0, responseHeaderBytes.Length);
                // 写入回应头部和内容之间的空行
                netstream.Write(new byte[] { 13, 10 }, 0, 2);

                // 写入回应的内容
                netstream.Write(responseBodyBytes, 0, responseBodyBytes.Length);

                // 关闭与客户端的连接
                client.Close();
                Console.ReadKey();
                break;
            }
            
            // 关闭服务器
            tcpListener.Stop();
        }
    }
}

     程序的输出结果和前面的用Socket实现的效果相同,这里就不再贴图了,这里实现的Web服务器都是建立控制台的应用程序来实现的,感兴趣的朋友也可以用Windows窗体进行实现,同时这里也只是简单列出了采用同步的方式进行实现的,同时TcpListener类和TcpClient类同时支持异步操作的方法,下面列出这个两个类中异步操作的方法如下表:

方法

说明

TcpListener

BeginAcceptTcpClient

开始一个异步操作接受一个传入的连接

EndAcceptTcpClient

异步接受传入的连接,并创建新的TcpClient对象来处理客户端的通信

TcpClient

BeginConnect

开始一个对远程主机连接的异步请求

EndConnect

异步接受传入的连接尝试。



三、总结

      到这里这篇文章就差不多介绍到这里了,本专题是介绍如何自定义一个简单Web服务器,通过这个专题希望大家可以对Web服务器的工作过程有一个简单的了解。

另外在这个专题里面我们是用IE浏览器进行发送客户请求的,所以后面专题将介绍自定义一个浏览器,通过我们自定义的浏览器来对Web服务器发送请求,然后在自己自定义的浏览器中把响应消息显示出来。


原文地址:点击打开链接

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了轴陀螺仪和轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值