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 10月 23 04:37 BaseHttpHandler.dll
-rw-r--r--. 1 root root 16124 10月 23 04:37 BaseHttpHandler.pdb
drwxr-xr-x. 2 root root 100 10月 23 04:31 htdocs
-rw-r--r--. 1 root root 713 10月 23 04:37 httpd.deps.json
-rw-r--r--. 1 root root 4608 10月 23 04:37 httpd.dll
-rw-r--r--. 1 root root 125952 10月 23 04:37 httpd.exe
-rw-r--r--. 1 root root 9732 10月 23 04:37 httpd.pdb
-rw-r--r--. 1 root root 317 10月 23 04:37 httpd.runtimeconfig.dev.json
-rw-r--r--. 1 root root 147 10月 23 04:37 httpd.runtimeconfig.json
-rw-r--r--. 1 root root 4460 10月 23 04:37 MIME.conf
drwxr-xr-x. 2 root root 23 10月 23 04:31 ref
-rw-r--r--. 1 root root 4096 10月 23 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
{