[C.C++] c# winform利用httplistener封装搭建http服务器

55 0
Honkers 昨天 14:15 | 显示全部楼层 |阅读模式

使用

  1. //http服务路由
  2. Dictionary<string, string> routes = new Dictionary<string, string> {
  3. {"/index","IndexController"},
  4. };
  5. //服务对象
  6. MyHttpServer httpServer;
  7. //启动http服务
  8. httpServer = new MyHttpServer(routes);//初始化,传入路由
  9. httpServer.respNotice += dataHandle;//回调方法,接收到http请求时触发
  10. httpServer.Start(12333);//端口
  11. /// <summary>
  12. /// 收到请求的回调函数
  13. /// </summary>
  14. /// <param name="data">客户端请求的数据</param>
  15. /// <param name="resp">respon对象</param>
  16. /// <param name="route">网址路径,如/api/test</param>
  17. /// <param name="request_type">请求类型,get或者post</param>
  18. public void dataHandle(Dictionary<string, string> data, HttpListenerResponse resp, string route = "", string request_type = "get")
  19. {
  20. string controller = routes.ContainsKey(route) ? routes[route] : "";
  21. //预定义返回的json数据
  22. Dictionary<string, string> resp_data = new Dictionary<string, string>();
  23. resp_data.Add("code", "1");
  24. resp_data.Add("data", "");
  25. resp_data.Add("time", "12345");
  26. resp_data.Add("msg", "ok ");
  27. //根据路由key的val匹配相应的算法,以下是自己的逻辑
  28. switch (controller)
  29. {
  30. case "IndexController":
  31. resp_json = JsonConvert.SerializeObject(resp_data);
  32. //输出结果
  33. httpServer.responData(resp_json, resp);
  34. break;
  35. default:
  36. httpServer.responData("404", resp);
  37. break;
  38. }
  39. }
复制代码

MyHttpServer.cs

  1. using HttpListenerPost;
  2. using Newtonsoft.Json;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. namespace PaddleOcrService.request.myhttp
  12. {
  13. public class MyHttpServer
  14. {
  15. //创建委托。用于通知
  16. public delegate void respNoticeDelegate(Dictionary<string, string> data, HttpListenerResponse resp,string route,string request_type = "get");
  17. public event respNoticeDelegate respNotice;
  18. private HttpListener listener = new HttpListener();
  19. private Dictionary<string, string> actionDict = new Dictionary<string, string>();
  20. private ReturnDataBase respObj;//返回的数据
  21. public string curr_path = "";
  22. //接收到的数据
  23. public Dictionary<string, string> data_rec = new Dictionary<string, string>();
  24. public MyHttpServer(Dictionary<string,string> routes = null)
  25. {
  26. if(routes != null)
  27. {
  28. //遍历字典路由
  29. foreach (KeyValuePair<string, string> kvp in routes)
  30. {
  31. AddPrefixes(kvp.Key, kvp.Value);
  32. }
  33. }
  34. }
  35. public void AddPrefixes(string url, string action)
  36. {
  37. actionDict.Add(url, action);
  38. }
  39. public void close()
  40. {
  41. listener.Stop();//停止监听
  42. //listener.Close();//释放资源
  43. }
  44. //开始监听
  45. public void Start(int port)
  46. {
  47. if (!HttpListener.IsSupported)
  48. {
  49. Console.WriteLine("无法在当前系统上运行服务(Windows XP SP2 or Server 2003)。" + DateTime.Now.ToString());
  50. return;
  51. }
  52. if (actionDict.Count <= 0)
  53. {
  54. System.Console.WriteLine("没有监听端口");
  55. }
  56. //监听url
  57. foreach (var item in actionDict)
  58. {
  59. var url = string.Format("http://127.0.0.1:{0}{1}", port, item.Key + "/");
  60. System.Console.WriteLine(url);
  61. listener.Prefixes.Add(url); //监听的是以item.Key + "/"+XXX接口
  62. }
  63. listener.Start();
  64. listener.BeginGetContext(Result, null);
  65. respObj = new ReturnDataBase();
  66. System.Console.WriteLine("开始监听");
  67. System.Console.Read();
  68. }
  69. private void Result(IAsyncResult asy)
  70. {
  71. if (!listener.IsListening) return;//如果已经停止监听了就直接返回
  72. listener.BeginGetContext(Result, null);
  73. var context = listener.EndGetContext(asy);
  74. var req = context.Request;
  75. var rsp = context.Response;
  76. //对接口url处理,解析出curr_path也就是当前路由
  77. string route=HandlerReq(req.RawUrl);//获取当前路由
  78. //对接口所传数据处理
  79. Dictionary<string, string> data = new Dictionary<string, string>();
  80. data= HandleHttpMethod(context,rsp,route);
  81. //将解析后的结果 通知
  82. dataNoticeEvent(data,rsp, route, context.Request.HttpMethod);
  83. }
  84. /// <summary>
  85. /// 输出结果(返回结果)
  86. /// </summary>
  87. /// <param name="content">结果</param>
  88. /// <param name="rsp">httprespon对象</param>
  89. /// <returns></returns>
  90. public string responData(string content,HttpListenerResponse rsp)
  91. {
  92. try
  93. {
  94. using (var stream = rsp.OutputStream)
  95. {
  96. 获取类名和方法名 格式: class.method
  97. //string class_name = actionDict.ContainsKey(route) ? actionDict[route] : "";
  98. /传入类名,利用反射创建对象并返回的数据,要返回给接口的
  99. //string content = respObj.GetDataMain(class_name, data);
  100. // response的outputStream输出数据的问题
  101. //方法一:程序以什么码表输出,一定要控制浏览器以什么码表打开
  102. //若"text/html;charset=UTF-8"写错,浏览器会提示下载
  103. rsp.StatusCode = 200;
  104. rsp.ContentType = "text/html;charset=UTF-8";//告诉客户端返回的ContentType类型为纯文本格式,编码为UTF-8
  105. rsp.AddHeader("Content-type", "application/json");//添加响应头信息
  106. rsp.ContentEncoding = Encoding.UTF8;
  107. rsp.AppendHeader("Access-Control-Allow-Origin", "*");//允许跨域
  108. rsp.AppendHeader("Access-Control-Allow-Credentials", "true");
  109. //后台跨域请求;//允许跨域
  110. //后台跨域请求,必须配置
  111. rsp.AppendHeader("Access-Control-Allow-Headers", "Authorization,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Requested-With");
  112. rsp.AppendHeader("Access-Control-Max-Age", "86400");
  113. byte[] dataByte = Encoding.UTF8.GetBytes(content);
  114. stream.Write(dataByte, 0, dataByte.Length);
  115. stream.Close();
  116. }
  117. }
  118. catch (Exception e)
  119. {
  120. rsp.Close();
  121. return e.Message;
  122. }
  123. rsp.Close();
  124. return "";
  125. }
  126. /// <summary>
  127. /// 对客户端来的url处理
  128. /// </summary>
  129. /// <param name="url"></param>
  130. private string HandlerReq(string url)
  131. {
  132. try
  133. {
  134. //url : /test?a=1
  135. System.Console.WriteLine("url : " + url);
  136. string[] arr_str= url.Split('?');
  137. if(arr_str.Length > 0)
  138. {
  139. return curr_path = arr_str[0];// 如下:/api/test
  140. }
  141. return "";
  142. }
  143. catch (Exception e)
  144. {
  145. return "";
  146. }
  147. }
  148. //处理接口所传数据 Post和Get 获取数据
  149. private Dictionary<string,string> HandleHttpMethod(HttpListenerContext context, HttpListenerResponse resp,string route)
  150. {
  151. Dictionary<string, string> return_data = new Dictionary<string, string>();
  152. data_rec.Clear();//先清空上一次http接收的数据
  153. string contentType = context.Request.ContentType == null ? "" : context.Request.ContentType;
  154. //1. ContentType = multipart/form-data
  155. if (contentType.Contains("multipart/form-data") )
  156. {
  157. //新建解析类(解析post数据)
  158. HttpListenerPostParaHelper parse = new HttpListenerPostParaHelper(context);
  159. List<HttpListenerPostValue> list = parse.GetHttpListenerPostValue();
  160. ;
  161. foreach (HttpListenerPostValue item in list)
  162. {
  163. string k = item.name;
  164. string value = "";
  165. if (item.type == 0)
  166. {
  167. //文本解析
  168. value = Encoding.UTF8.GetString(item.datas).Replace("\r\n", "");
  169. }
  170. else
  171. {
  172. //byte数组转文件
  173. File.WriteAllBytes(@"D:\test.png", item.datas);
  174. value = @"D:\test.png";
  175. }
  176. dataRecAdd(k,value);
  177. }
  178. return_data = data_rec;
  179. return return_data;
  180. }
  181. //2.ContentType=application/json
  182. if (contentType.Contains("application/json"))
  183. {
  184. try
  185. {
  186. Stream stream = context.Request.InputStream;
  187. StreamReader reader = new StreamReader(stream, Encoding.UTF8);
  188. string json = reader.ReadToEnd();
  189. Dictionary<string, string> DicContent = new Dictionary<string, string>();
  190. if (string.IsNullOrEmpty(json)) return return_data ;
  191. if (json == "[]" || json == "") return return_data;
  192. data_rec = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
  193. return_data = data_rec;//返回的数据
  194. }
  195. catch (Exception ex)
  196. {
  197. return return_data;
  198. }
  199. return return_data;
  200. }
  201. //3. ContentType = text/html等类型 就使用别的解析算法
  202. switch (context.Request.HttpMethod)
  203. {
  204. case "GET":
  205. var data = context.Request.QueryString;
  206. // 没解决乱码问题,用url进行解析正常
  207. string url = context.Request.Url.ToString();
  208. string[] pars = url.Split('?');
  209. string content = "";
  210. if (pars.Length == 0)
  211. {
  212. return return_data;
  213. }
  214. if (pars.Length <= 1) return return_data;
  215. string canshus = pars[1];
  216. if (canshus.Length > 0)
  217. {
  218. string[] canshu = canshus.Split('&');
  219. foreach (string i in canshu)
  220. {
  221. string[] messages = i.Split('=');
  222. dataRecAdd(messages[0], messages[1]);
  223. //content += "参数为:" + messages[0] + " 值为:" + messages[1];
  224. }
  225. return_data = data_rec;
  226. }
  227. return return_data;
  228. break;
  229. }
  230. return return_data;
  231. }
  232. /// <summary>
  233. /// 将解析后的数据通知事件
  234. /// </summary>
  235. /// <param name="data">解析后的字典数据</param>
  236. /// <param name="rsp">respon对象</param>
  237. /// <param name="route">路由</param>
  238. /// <param name="method">方法</param>
  239. public void dataNoticeEvent(Dictionary<string, string> data,HttpListenerResponse rsp,string route, string method = "unkonwn")
  240. {
  241. //通知
  242. //if (data_rec.Count > 1)
  243. //{
  244. // respNotice?.Invoke(data_rec, rsp,route,method);
  245. //}
  246. respNotice?.Invoke(data, rsp, route, method);
  247. }
  248. public void dataRecAdd(string k ,string v)
  249. {
  250. if (data_rec.ContainsKey(k))
  251. {
  252. data_rec[k] = v;
  253. }
  254. else
  255. {
  256. data_rec.Add(k, v);
  257. }
  258. }
  259. }
  260. class ReturnDataBase
  261. {
  262. public string GetDataMain(string class_method, Dictionary<string, string> rec_data)
  263. {
  264. string[] class_arr = class_method.Split('.');//分割类名跟方法
  265. string class_name,method;
  266. if (class_arr.Length == 1) class_name = class_arr[0];
  267. if (class_arr.Length == 2) method = class_arr[1];
  268. if (class_arr.Length == 0) return "";
  269. return "cesh";
  270. }
  271. }
  272. }
复制代码

HttpListenerPostValue.cs

这个类主要用于解析content-type为multipart/form-data时解析数据

  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace HttpListenerPost
  9. {
  10. /// <summary>
  11. /// HttpListenner监听Post请求参数值实体
  12. /// </summary>
  13. public class HttpListenerPostValue
  14. {
  15. /// <summary>
  16. /// 0=> 参数
  17. /// 1=> 文件
  18. /// </summary>
  19. public int type = 0;
  20. public string name;
  21. public byte[] datas;
  22. }
  23. /// <summary>
  24. /// 获取Post请求中的参数和值帮助类
  25. /// </summary>
  26. public class HttpListenerPostParaHelper
  27. {
  28. private HttpListenerContext request;
  29. public HttpListenerPostParaHelper(HttpListenerContext request)
  30. {
  31. this.request = request;
  32. }
  33. private bool CompareBytes(byte[] source, byte[] comparison)
  34. {
  35. try
  36. {
  37. int count = source.Length;
  38. if (source.Length != comparison.Length)
  39. return false;
  40. for (int i = 0; i < count; i++)
  41. if (source[i] != comparison[i])
  42. return false;
  43. return true;
  44. }
  45. catch
  46. {
  47. return false;
  48. }
  49. }
  50. private byte[] ReadLineAsBytes(Stream SourceStream)
  51. {
  52. var resultStream = new MemoryStream();
  53. while (true)
  54. {
  55. int data = SourceStream.ReadByte();
  56. resultStream.WriteByte((byte)data);
  57. if (data == 10)
  58. break;
  59. }
  60. resultStream.Position = 0;
  61. byte[] dataBytes = new byte[resultStream.Length];
  62. resultStream.Read(dataBytes, 0, dataBytes.Length);
  63. return dataBytes;
  64. }
  65. /// <summary>
  66. /// 获取Post过来的参数和数据
  67. /// </summary>
  68. /// <returns></returns>
  69. public List<HttpListenerPostValue> GetHttpListenerPostValue()
  70. {
  71. try
  72. {
  73. List<HttpListenerPostValue> HttpListenerPostValueList = new List<HttpListenerPostValue>();
  74. if (request.Request.ContentType.Length > 20 && string.Compare(request.Request.ContentType.Substring(0, 20), "multipart/form-data;", true) == 0)
  75. {
  76. string[] HttpListenerPostValue = request.Request.ContentType.Split(';').Skip(1).ToArray();
  77. string boundary = string.Join(";", HttpListenerPostValue).Replace("boundary=", "").Trim();
  78. byte[] ChunkBoundary = Encoding.UTF8.GetBytes("--" + boundary + "\r\n");
  79. byte[] EndBoundary = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n");
  80. Stream SourceStream = request.Request.InputStream;
  81. var resultStream = new MemoryStream();
  82. bool CanMoveNext = true;
  83. HttpListenerPostValue data = null;
  84. while (CanMoveNext)
  85. {
  86. byte[] currentChunk = ReadLineAsBytes(SourceStream);
  87. if (!Encoding.UTF8.GetString(currentChunk).Equals("\r\n"))
  88. resultStream.Write(currentChunk, 0, currentChunk.Length);
  89. if (CompareBytes(ChunkBoundary, currentChunk))
  90. {
  91. byte[] result = new byte[resultStream.Length - ChunkBoundary.Length];
  92. resultStream.Position = 0;
  93. resultStream.Read(result, 0, result.Length);
  94. CanMoveNext = true;
  95. if (result.Length > 0)
  96. data.datas = result;
  97. data = new HttpListenerPostValue();
  98. HttpListenerPostValueList.Add(data);
  99. resultStream.Dispose();
  100. resultStream = new MemoryStream();
  101. }
  102. else if (Encoding.UTF8.GetString(currentChunk).Contains("Content-Disposition"))
  103. {
  104. byte[] result = new byte[resultStream.Length - 2];
  105. resultStream.Position = 0;
  106. resultStream.Read(result, 0, result.Length);
  107. CanMoveNext = true;
  108. data.name = Encoding.UTF8.GetString(result).Replace("Content-Disposition: form-data; name="", "").Replace(""", "").Split(';')[0];
  109. resultStream.Dispose();
  110. resultStream = new MemoryStream();
  111. }
  112. else if (Encoding.UTF8.GetString(currentChunk).Contains("Content-Type"))
  113. {
  114. CanMoveNext = true;
  115. data.type = 1;
  116. resultStream.Dispose();
  117. resultStream = new MemoryStream();
  118. }
  119. else if (CompareBytes(EndBoundary, currentChunk))
  120. {
  121. byte[] result = new byte[resultStream.Length - EndBoundary.Length - 2];
  122. resultStream.Position = 0;
  123. resultStream.Read(result, 0, result.Length);
  124. data.datas = result;
  125. resultStream.Dispose();
  126. CanMoveNext = false;
  127. }
  128. }
  129. }
  130. return HttpListenerPostValueList;
  131. }
  132. catch (Exception ex)
  133. {
  134. return null;
  135. }
  136. }
  137. }
  138. }
复制代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2025 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行