Web协议-HTTP协议实现

Posted Walk in loosing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web协议-HTTP协议实现相关的知识,希望对你有一定的参考价值。

生活中充满了各种网站,那么网站的基础HTTP协议是什么样的,平时都是使用网页,或者看书上说HTTP协议。最近讲实现HTTP到Webservice系列协议的简单程序,并且开发代码,供爱学习的人理解HTTP协议到Webservice协议。

本次开发使用NetCore5.0,实现的服务可以运行在linux和windows。原理通了只要有精力任何有tcp的开发语言都能自己实现http服务器,不限于C#,可以用C、C++、Java、等等自己实现HTTP服务器。目前比较简单,抓紧学习(哈哈)

代码地址:https://download.csdn.net/download/zhanglianzhu_91/34029518

程序效果


linux测试

[root@localhost httpd]# ll
总用量 200
-rw-r--r--. 1 root root  14848 1023 04:37 BaseHttpHandler.dll
-rw-r--r--. 1 root root  16124 1023 04:37 BaseHttpHandler.pdb
drwxr-xr-x. 2 root root    100 1023 04:31 htdocs
-rw-r--r--. 1 root root    713 1023 04:37 httpd.deps.json
-rw-r--r--. 1 root root   4608 1023 04:37 httpd.dll
-rw-r--r--. 1 root root 125952 1023 04:37 httpd.exe
-rw-r--r--. 1 root root   9732 1023 04:37 httpd.pdb
-rw-r--r--. 1 root root    317 1023 04:37 httpd.runtimeconfig.dev.json
-rw-r--r--. 1 root root    147 1023 04:37 httpd.runtimeconfig.json
-rw-r--r--. 1 root root   4460 1023 04:37 MIME.conf
drwxr-xr-x. 2 root root     23 1023 04:31 ref
-rw-r--r--. 1 root root   4096 1023 04:37 UserDeal.dll
[root@localhost httpd]# dotnet httpd.dll
如果要设定IP请输入,否则回车:
172.25.137.27
04:38:47:启动httpd服务器
04:38:47:启动TCP服务成功
04:38:47:启动在:172.25.137.27:50003

主要源码
程序入口

using BaseHttpHandler;
using System;

namespace httpd
{
    class Program
    {
        static void Main(string[] args)
        {
            HttpdServer server = new HttpdServer();
            string err;
            Util.WriteLog("启动httpd服务器");
            bool ret=server.StartServer(50003, out err);
            if(err!="")
            {
                Util.WriteLog("启动服务失败:"+err);
            }
            Console.ReadLine();
        }
    }
}

http服务类-启动端口侦听等

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

namespace BaseHttpHandler
{
    ///<summary  NoteObject="Class">
    /// [功能描述:zlz实现的http服务类,实现http服务器] <para/>
    /// [创建者:zlz] <para/>
    /// [创建时间:zlz实现的http服务类,实现http服务器] <para/>
    ///<说明>
    ///  [说明:]<para/>
    ///</说明>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///</summary>
    public class HttpdServer
    {
        /// <summary>
        /// 网络服务对象
        /// </summary>
        Socket serverSocket = null;

        /// <summary>
        /// 启动http服务
        /// </summary>
        /// <param name="port">端口</param>
        /// <param name="err">错误</param>
        /// <returns>是否启动成功</returns>
        public bool StartServer(int port, out string err)
        {
            err = "";
            #region 读取MIME配置
            //读取mime配置
            string mimename = Path.Combine(AppContext.BaseDirectory, "MIME.conf");
            Util.DicMime.Clear();
            //解析mime
            if (File.Exists(mimename))
            {
                StreamReader sr = new StreamReader(mimename, Encoding.UTF8);
                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    if (line != "")
                    {
                        string[] mimeArr = line.Split('^');
                        if (mimeArr.Length == 2 && (!Util.DicMime.ContainsKey("." + mimeArr[0])))
                        {
                            Util.DicMime.Add("." + mimeArr[0], mimeArr[1]);
                        }
                    }
                }
                sr.Close();
                sr.Dispose();
            }
            #endregion
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //得到当前电脑IP
            IPAddress hostIP = Util.GetIpv4Str();
            //判断端口是否被占用
            if (Util.PortInUse(port))
            {
                err = "当前电脑端口:" + port + "已经被占用!";
                Util.WriteLog(err);
                return false;
            }
            //创建终节点
            IPEndPoint endPoint = new IPEndPoint(hostIP, port);
            serverSocket.Bind(endPoint);
            try
            {
                //开始侦听
                serverSocket.Listen(200);
                Util.WriteLog("启动TCP服务成功");
                Util.WriteLog("启动在:" + hostIP.ToString() + ":" + port);
                Thread tcpThread = new Thread(new ThreadStart(ServerTcpListenMain));
                tcpThread.Start();
            }
            catch (Exception ex)
            {
                err = ex.Message;
                Util.WriteLog(err);
                return false;
            }
            return true;
        }

        /// <summary>
        /// 服务端侦听主线程,用死循环侦听服务端口收到的连接
        /// </summary>
        private void ServerTcpListenMain()
        {
            while (true)
            {
                try
                {
                    //有新连接过来,开启子进程处理连接
                    Socket client = serverSocket.Accept();
                    if (client != null)
                    {
                        //用新线程处理请求
                        DealClientRequest deal = new DealClientRequest(client);
                    }
                }
                catch (Exception ex)
                {
                    Util.WriteLog("服务端主侦听异常:" + ex.Message);
                }
            }
        }


    }
}

请求处理类-开启请求处理线程和请求解析

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BaseHttpHandler
{
    ///<summary  NoteObject="Class">
    /// [功能描述:用来处理客户端的请求] <para/>
    /// [创建者:zlz] <para/>
    /// [创建时间:用来处理客户端的请求] <para/>
    ///<说明>
    ///  [说明:]<para/>
    ///</说明>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///</summary>
    public class DealClientRequest
    {
        /// <summary>
        /// 客户端
        /// </summary>
        private Socket client = null;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="Client"></param>
        public DealClientRequest(Socket Client)
        {
            client = Client;
            Thread newThread = new Thread(DealRequest);
            newThread.Start();
        }

        /// <summary>
        /// 客户端服务
        /// </summary>
        public void DealRequest()
        {
            string data = null;
            byte[] bytes = new byte[4096];
            try
            {
                StringBuilder sb = new StringBuilder();
                int dataLen = 0;
                client.ReceiveTimeout = 2000;
                while ((dataLen = client.Receive(bytes)) != 0 || sb.Length == 0)
                {
                    if (dataLen < 0)
                    {
                        break;
                    }
                    data = System.Text.Encoding.Default.GetString(bytes, 0, dataLen);
                    sb.Append(data);
                    if (client.Available == 0)
                    {
                        break;
                    }
                }
                string allStr = sb.ToString();
                Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:收到:") + allStr);
                HttpContex contex = new HttpContex(allStr, client);
                HttpHandler handler = new HttpHandler();
                handler.Invok(contex);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:处理客户端请求异常,") + ex.Message);
            }
            finally
            {
                if (client != null)
                {
                    client.Close();
                }
            }
        }
    }
}

http主处理

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Runtime.Loader;

namespace BaseHttpHandler
{
    ///<summary  NoteObject="Class">
    /// [功能描述:Http执行句柄] <para/>
    /// [创建者:zlz] <para/>
    /// [创建时间:Http执行句柄] <para/>
    ///<说明>
    ///  [说明:]<para/>
    ///</说明>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///</summary>
    public class HttpHandler
    {
        /// <summary>
        /// http上下文
        /// </summary>
        public HttpContex Contex;

        /// <summary>
        /// 执行请求
        /// </summary>
        /// <param name="contex"></param>
        public void Invok(HttpContex contex)
        {
            Contex = contex;
            //是POST类型的请求
            if (contex.HRequest.GetReqType() == "POST")
            {
                string path = contex.HRequest.GetReqPath();
                string url = path.Split('?')[0];
                string[] arr = url.Split('/');
                if (arr.Length > 2)
                {
                    string dllName = arr[1];
                    string classFullName = arr[2];
                    string ret = ProcessRequestReflect(dllName, classFullName);
                    contex.HResponse.Write(ret);
                }
                else
                {
                    contex.HResponse.Write("-1^错误的请求路径!");
                }
            }
        }

        /// <summary>
        /// 执行方法
        /// </summary>
        /// <param name="dllName"></param>
        /// <param name="className"></param>
        /// <returns></returns>
        private string ProcessRequestReflect(string dllName, string className)
        {
            dllName = Path.Combine(AppContext.BaseDirectory, dllName + ".dll");
            Assembly assembly = Assembly.LoadFrom(dllName);
            //创建实例
            object obj = assembly.CreateInstance(className, false);
            if (obj != null)
            {
                Util.SetPropertyValue(obj, "Contex", Contex);
                //获得前台传入的要调用的方法名称
                string method = Contex.HRequest.GetReqPara("Method");
                //方法名称不为空,找到并执行方法
                if (!string.IsNullOrEmpty(method))
                {
                    //根据名称获得方法信息
                    MethodInfo methodInfo = obj.GetType().GetMethod(method, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
                    //没找到方法就抛出错误信息
                    if (methodInfo == null)
                    {
                        return "-1^未找到后台方法“" + method + "”!";
                    }
                    object ret = methodInfo.Invoke(obj, null);
                    if (ret == null)
                    {
                        return null;
                    }
                    //执行找到的方法,并返回结果
                    return (string)ret;
                }
                else
                {
                    return "-1^方法名Method不能为空!";
                }
            }
            else
            {
                return "-1^处理类不存在!";
            }
        }
    }
}

上下文对象

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace BaseHttpHandler
{
    ///<summary  NoteObject="Class">
    /// [功能描述:包装简单的上下文对象,用来响应客户端的消息] <para/>
    /// [创建者:zlz] <para/>
    /// [创建时间:包装简单的上下文对象,用来响应来着客户端的消息] <para/>
    ///<说明>
    ///  [说明:]<para/>
    ///</说明>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///<修改记录>
    ///    [修改时间:本次修改时间]<para/>
    ///    [修改内容:本次修改内容]<para/>
    ///</修改记录>
    ///</summary>
    public class HttpContex
    {
        /// <summary>
        /// 请求对象
        /// </summary>
        public Request HRequest
        {
            get;
            set;
        }

        /// <summary>
        /// 响应对象
        /// </summary>
        public Response HResponse
        {
            get;
            set;
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="data"></param>
        /// <param name="Client"></param>
        public HttpContex(string data, Socket Client)
        {
            HRequest = new Request(data, Client);
            HResponse = new Response(data, Client);
        }
    }
}

Request对象

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net.Sockets;

namespace BaseHttpHandler
{