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

 前言:

经过前面的专题中对网络层协议和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服务器发送请求,然后在自己自定义的浏览器中把响应消息显示出来。


原文地址:点击打开链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
城市应急指挥系统是智慧城市建设的重要组成部分,旨在提高城市对突发事件的预防和处置能力。系统背景源于自然灾害和事故灾难频发,如汶川地震和日本大地震等,这些事件造成了巨大的人员伤亡和财产损失。随着城市化进程的加快,应急信息化建设面临信息资源分散、管理标准不统一等问题,需要通过统筹管理和技术创新来解决。 系统的设计思路是通过先进的技术手段,如物联网、射频识别、卫星定位等,构建一个具有强大信息感知和通信能力的网络和平台。这将促进不同部门和层次之间的信息共享、交流和整合,提高城市资源的利用效率,满足城市对各种信息的获取和使用需求。在“十二五”期间,应急信息化工作将依托这些技术,实现动态监控、风险管理、预警以及统一指挥调度。 应急指挥系统的建设目标是实现快速有效的应对各种突发事件,保障人民生命财产安全,减少社会危害和经济损失。系统将包括预测预警、模拟演练、辅助决策、态势分析等功能,以及应急值守、预案管理、GIS应用等基本应用。此外,还包括支撑平台的建设,如接警中心、视频会议、统一通信等基础设施。 系统的实施将涉及到应急网络建设、应急指挥、视频监控、卫星通信等多个方面。通过高度集成的系统,建立统一的信息接收和处理平台,实现多渠道接入和融合指挥调度。此外,还包括应急指挥中心基础平台建设、固定和移动应急指挥通信系统建设,以及应急队伍建设,确保能够迅速响应并有效处置各类突发事件。 项目的意义在于,它不仅是提升灾害监测预报水平和预警能力的重要科技支撑,也是实现预防和减轻重大灾害和事故损失的关键。通过实施城市应急指挥系统,可以加强社会管理和公共服务,构建和谐社会,为打造平安城市提供坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值