鹿我所录的博客

记录我在学习C#中的点点滴滴,记录下以备后来人借鉴。

 

C#自制Web 服务器开发:用C#开发自己的Web服务器

当输入:127.0.0.1:5050

GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:5050
DNT: 1
Connection: Keep-Alive
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B



http://127.0.0.1:5050/index.html

GET /index.html HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:5050
DNT: 1
Connection: Keep-Alive
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B


提交表单

POST / HTTP/1.1
Host: 127.0.0.1:5050
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 51

txtName=&txtClass=&txtPassword=&Submit=%CC%E1%BD%BB


提交表单 2

POST /CCC.asp HTTP/1.1
Host: 127.0.0.1:5050
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 68

txtName=name&txtClass=class&txtPassword=password&Submit=%CC%E1%BD%BB


提交表单3
POST /CCC.asp HTTP/1.1
Host: 127.0.0.1:5050
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Cookie: s_pers=%20s_fid%3D5E4387B367FCC613-0DC7FD9C6D76C087%7C1453856077838%3B%20s_vs%3D1%7C1390785877860%3B%20s_nr%3D1390784077867-New%7C1422320077867%3B
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 93

txtName=%D5%C5%C8%FD&txtClass=%B8%DF%D2%BB%B6%FE%B0%E0&txtPassword=990749&Submit=%CC%E1%BD%BB
View Code

以上是 浏览器在浏览时发送给服务器的数据内容.在不同情况下会有所不同.不过,一般数据量都很小.

以上的  %D5%C5%C8%FD  实际上是 urlencode 编码方式:在程序开发的过程,需要对其进行解码

 

由于IIS的不稳定性和难实施性(对操作系统太挑剔),一直想做个自己的轻量级Web服务器。

今天终于抽出时间,借助网络上的实例,实现了自己的服务器,计划以后在项目开发时尝试取代IIS服务器。

在此把整体实现过程记录下,以备后用。

技术实现原理:

1.需要了解HTTP的工作原理

2.需要了解基于C#的SOCKET编程,TcpListener类对象,监听端口

一、启动VS2005,新建一个控制台程序,命名:ConsoleApplication1

二、在添加CS文件,使名:MyWebServer.cs

三、实现类MyWebServer,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace WindowsFormsApplication1
{
    class MyWebServer
    {
        private TcpListener myListener;
        private int port = 8899; // 选者任何闲置端口
        //开始兼听端口
        //同时启动一个兼听进程
        public MyWebServer()
        {
            try
            {
                //开始兼听端口
                myListener = new TcpListener(port);
                myListener.Start();
                Console.WriteLine("Web Server Running... Press ^C to Stop...");
                //同时启动一个兼听进程 ''StartListen''
                Thread th = new Thread(new ThreadStart(StartListen));
                th.Start();
            }
            catch (Exception e)
            {
                Console.WriteLine("兼听端口时发生错误 :" + e.ToString());
            }
        }
        public void SendHeader(string sHttpVersion, string sMIMEHeader, int iTotBytes, string sStatusCode, ref Socket mySocket)
        {

            String sBuffer = "";
            if (sMIMEHeader.Length == 0)
            {
                sMIMEHeader = "text/html"; // 默认 text/html
            }
            sBuffer = sBuffer + sHttpVersion + sStatusCode + "\r\n";
            sBuffer = sBuffer + "Server: cx1193719-b\r\n";
            sBuffer = sBuffer + "Content-Type: " + sMIMEHeader + "\r\n";
            sBuffer = sBuffer + "Accept-Ranges: bytes\r\n";
            sBuffer = sBuffer + "Content-Length: " + iTotBytes + "\r\n\r\n";
            Byte[] bSendData = Encoding.ASCII.GetBytes(sBuffer);
            SendToBrowser(bSendData, ref mySocket);
            Console.WriteLine("Total Bytes : " + iTotBytes.ToString());
        }
        public void SendToBrowser(String sData, ref Socket mySocket)
        {
            SendToBrowser(Encoding.ASCII.GetBytes(sData), ref mySocket);
        }

        public void SendToBrowser(Byte[] bSendData, ref Socket mySocket)
        {
            int numBytes = 0;

            try
            {
                if (mySocket.Connected)
                {
                    if ((numBytes = mySocket.Send(bSendData, bSendData.Length, 0)) == -1)
                        Console.WriteLine("Socket Error cannot Send Packet");
                    else
                    {
                        Console.WriteLine("No. of bytes send {0}", numBytes);
                    }
                }
                else
                    Console.WriteLine("连接失败....");
            }
            catch (Exception e)
            {
                Console.WriteLine("发生错误 : {0} ", e);

            }
        }
        public void StartListen()
        {

            int iStartPos = 0;
            String sRequest;
            String sDirName;
            String sRequestedFile;
            String sErrorMessage;
            String sLocalDir;
            /////////////////////////////////////注意设定你自己的虚拟目录/////////////////////////////////////
            String sMyWebServerRoot = "C:\\Cassini\"; //设置你的虚拟目录
            //////////////////////////
            String sFormattedMessage = "";
            String sResponse = "";


            while (true)
            {
                //接受新连接
                Socket mySocket = myListener.AcceptSocket();

                Console.WriteLine("Socket Type " + mySocket.SocketType);
                if (mySocket.Connected)
                {
                    Console.WriteLine("\nClient Connected!!\n==================\nCLient IP {0}\n", mySocket.RemoteEndPoint);

                    Byte[] bReceive = new Byte[1024];
                    int i = mySocket.Receive(bReceive, bReceive.Length, 0);


                    //转换成字符串类型
                    string sBuffer = Encoding.ASCII.GetString(bReceive);


                    //只处理"get"请求类型
                    if (sBuffer.Substring(0, 3) != "GET")
                    {
                        Console.WriteLine("只处理get请求类型..");
                        mySocket.Close();
                        return;
                    }

                    // 查找 "HTTP" 的位置
                    iStartPos = sBuffer.IndexOf("HTTP", 1);


                    string sHttpVersion = sBuffer.Substring(iStartPos, 8);


                    // 得到请求类型和文件目录文件名
                    sRequest = sBuffer.Substring(0, iStartPos - 1);

                    sRequest.Replace("\", "/");


                    //如果结尾不是文件名也不是以"/"结尾则加"/"
                    if ((sRequest.IndexOf(".") < 1) && (!sRequest.EndsWith("/")))
                    {
                        sRequest = sRequest + "/";
                    }


                    //得带请求文件名
                    iStartPos = sRequest.LastIndexOf("/") + 1;
                    sRequestedFile = sRequest.Substring(iStartPos);


                    //得到请求文件目录
                    sDirName = sRequest.Substring(sRequest.IndexOf("/"), sRequest.LastIndexOf("/") - 3);


                    //获取虚拟目录物理路径
                    sLocalDir = sMyWebServerRoot;

                    Console.WriteLine("请求文件目录 : " + sLocalDir);

                    if (sLocalDir.Length == 0)
                    {
                        sErrorMessage = "<H2>Error!! Requested Directory does not exists</H2><Br>";
                        SendHeader(sHttpVersion, "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
                        SendToBrowser(sErrorMessage, ref mySocket);
                        mySocket.Close();
                        continue;
                    }


                    if (sRequestedFile.Length == 0)
                    {
                        // 取得请求文件名
                        sRequestedFile = "index.html";
                    }


                    /////////////////////////////////////////////////////////////////////
                    // 取得请求文件类型(设定为text/html)
                    /////////////////////////////////////////////////////////////////////

                    String sMimeType = "text/html";

                    string sPhysicalFilePath = sLocalDir + sRequestedFile;
                    Console.WriteLine("请求文件: " + sPhysicalFilePath);


                    if (File.Exists(sPhysicalFilePath) == false)
                    {

                        sErrorMessage = "<script language='javascript'>alert('你好呀,我不是IIS服务器!');</script>";
                        //SendHeader(sHttpVersion, "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
                        //SendToBrowser(sErrorMessage, ref mySocket);
                        byte[] bytes = Encoding.GetEncoding("GB2312").GetBytes(sErrorMessage);
                        SendHeader(sHttpVersion, sMimeType, bytes.Length, " 200 OK", ref mySocket);
                        SendToBrowser(bytes, ref mySocket);
                        //Console.WriteLine(sFormattedMessage);
                    }
                    else
                    {
                        int iTotBytes = 0;

                        sResponse = "";

                        FileStream fs = new FileStream(sPhysicalFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);

                        BinaryReader reader = new BinaryReader(fs);
                        byte[] bytes = new byte[fs.Length];
                        int read;
                        while ((read = reader.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            sResponse = sResponse + Encoding.ASCII.GetString(bytes, 0, read);

                            iTotBytes = iTotBytes + read;

                        }
                        reader.Close();
                        fs.Close();

                        SendHeader(sHttpVersion, sMimeType, iTotBytes, " 200 OK", ref mySocket);
                        SendToBrowser(bytes, ref mySocket);
                        //mySocket.Send(bytes, bytes.Length,0);

                    }
                    mySocket.Close();
                }
            }
        }
    }
}

四、编辑Program.cs,启动监听

static void Main(string[] args)
        {
            MyWebServer MWS = new MyWebServer();
            Console.Read();
        }

 

 

 

posted on 2014-02-08 21:10  鹿我所录  阅读(11283)  评论(1编辑  收藏  举报

导航