1.问题描述
做一个二维码摆渡机的发送端和接收端程序,用于网络物理隔离。摆渡机是第三方厂家的设备,该设备提供一个接口用于接收发送端传输的数据,摆渡机处理该数据并调用接收端的接口,将数据传递给接收端。
本文主要记录接收端程序如何使用 HttpListener 进行监听HTTP请求,并且解析POST请求中携带的参数。如何构造 content-type 为 multipart/form-data; boundary= 的POST请求,请参考:https://cylycgs.blog.csdn.net/article/details/101019468
下面是发送端和接收端的截图:
2.使用HttpListener监听
关于HttpListener的官方文档在这里:https://docs.microsoft.com/en-us/dotnet/api/system.net.httplistener?view=netframework-4.5
如下是关于如何使用 HttpListener 的相关代码,有详细的注释:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Windows.Forms;
namespace HttpListenerDemo
{
public partial class FrmResponse : Form
{
private static HttpListener httpListener = null;
public FrmResponse()
{
InitializeComponent();
}
private void GetHttpListenerCallBack(IAsyncResult ar)
{
try
{
httpListener = ar.AsyncState as HttpListener;
HttpListenerContext context = httpListener.EndGetContext(ar);
httpListener.BeginGetContext(new AsyncCallback(GetHttpListenerCallBack), httpListener);
var request = context.Request;
var response = context.Response;
response.ContentType = "text/plain;charset=UTF-8";
response.AddHeader("Content-type", "text/plain");
response.ContentEncoding = Encoding.UTF8;
string returnObj = null;
if (request.HttpMethod == "POST" && request.ContentLength64 > 0)
{
returnObj = HandleRequest(request, response);
}
else
{
returnObj = $"必须是POST请求,并且必须传参";
response.StatusDescription = "400";
response.StatusCode = 400;
}
var returnByteArr = Encoding.UTF8.GetBytes(returnObj);
try
{
using (var stream = response.OutputStream)
{
stream.Write(returnByteArr, 0, returnByteArr.Length);
ShowMsg($"HTTP请求响应内容:{returnObj}");
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"发生异常:{ex.ToString()}");
ShowMsg($"发生异常:{ ex.ToString()}");
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"发生异常:{ex.ToString()}");
ShowMsg($"发生异常:{ ex.ToString()}");
}
}
private string HandleRequest(HttpListenerRequest request, HttpListenerResponse response)
{
NameValueCollection myCol = request.QueryString;
var contentType = request.ContentType;
try
{
HttpListenerPostParaHelper httppost = new HttpListenerPostParaHelper(request);
List<HttpListenerPostValue> lst = httppost.GetHttpListenerPostValue();
var data = "";
foreach (var key in lst)
{
if (key.type == 0)
{
string value = Encoding.UTF8.GetString(key.datas).Replace("\r\n", "");
if (key.name == "QUERY_STRING")
{
data = value;
Console.WriteLine(value);
}
}
}
response.StatusDescription = "200";
response.StatusCode = 200;
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"接收数据完成:{data.Trim()},时间:{DateTime.Now.ToString()}");
ShowMsg($"接收数据完成:{data.Trim()}");
return $"接收数据完成";
}
catch (Exception ex)
{
response.StatusDescription = "404";
response.StatusCode = 404;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"在接收数据时发生错误:{ex.ToString()}");
return $"在接收数据时发生错误:{ex.ToString()}";
}
}
private void btn_开启HTTP监听_Click(object sender, EventArgs e)
{
if (httpListener == null)
{
httpListener = new HttpListener();
httpListener.Prefixes.Add($"{txt_接收端地址.Text.Trim()}");
httpListener.Start();
httpListener.BeginGetContext(new AsyncCallback(GetHttpListenerCallBack), httpListener);
ShowMsg($"{txt_接收端地址.Text.Trim()} HTTP监听已开启");
}
}
private delegate void dlgShowMsg(string msg);
private void ShowMsg(string msg)
{
if (richTextBox1.InvokeRequired)
{
dlgShowMsg dlg = new dlgShowMsg(ShowMsg);
richTextBox1.Invoke(dlg, msg);
}
else
{
if (richTextBox1.Lines.Length >= 1000)
richTextBox1.Clear();
richTextBox1.AppendText($"{Environment.NewLine}{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} {msg}");
}
}
private void btn_清空HTTP日志_Click(object sender, EventArgs e)
{
richTextBox1.Clear();
}
}
}
解析POST请求中的参数,写了一个 HttpListenerPostParaHelper 帮助类,代码如下:
#region << 版 本 注 释 >>
#endregion << 版 本 注 释 >>
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
namespace HttpListenerDemo
{
internal class HttpListenerPostParaHelper
{
#region <变量>
private HttpListenerRequest request;
#endregion <变量>
#region <方法>
public HttpListenerPostParaHelper(HttpListenerRequest request)
{
this.request = request;
}
private bool CompareBytes(byte[] source, byte[] comparison)
{
try
{
int count = source.Length;
if (source.Length != comparison.Length)
return false;
for (int i = 0; i < count; i++)
if (source[i] != comparison[i])
return false;
return true;
}
catch
{
return false;
}
}
private byte[] ReadLineAsBytes(Stream SourceStream)
{
var resultStream = new MemoryStream();
while (true)
{
int data = SourceStream.ReadByte();
resultStream.WriteByte((byte)data);
if (data == 10)
break;
}
resultStream.Position = 0;
byte[] dataBytes = new byte[resultStream.Length];
resultStream.Read(dataBytes, 0, dataBytes.Length);
return dataBytes;
}
public List<HttpListenerPostValue> GetHttpListenerPostValue()
{
try
{
List<HttpListenerPostValue> HttpListenerPostValueList = new List<HttpListenerPostValue>();
if (request.ContentType.Length > 20 && string.Compare(request.ContentType.Substring(0, 20), "multipart/form-data;", true) == 0)
{
string[] HttpListenerPostValue = request.ContentType.Split(';').Skip(1).ToArray();
string boundary = string.Join(";", HttpListenerPostValue).Replace("boundary=", "").Trim();
byte[] ChunkBoundary = Encoding.UTF8.GetBytes("--" + boundary + "\r\n");
byte[] EndBoundary = Encoding.UTF8.GetBytes("--" + boundary + "--\r\n");
Stream SourceStream = request.InputStream;
var resultStream = new MemoryStream();
bool CanMoveNext = true;
HttpListenerPostValue data = null;
while (CanMoveNext)
{
byte[] currentChunk = ReadLineAsBytes(SourceStream);
if (!Encoding.UTF8.GetString(currentChunk).Equals("\r\n"))
resultStream.Write(currentChunk, 0, currentChunk.Length);
if (CompareBytes(ChunkBoundary, currentChunk))
{
byte[] result = new byte[resultStream.Length - ChunkBoundary.Length];
resultStream.Position = 0;
resultStream.Read(result, 0, result.Length);
CanMoveNext = true;
if (result.Length > 0)
data.datas = result;
data = new HttpListenerPostValue();
HttpListenerPostValueList.Add(data);
resultStream.Dispose();
resultStream = new MemoryStream();
}
else if (Encoding.UTF8.GetString(currentChunk).Contains("Content-Disposition"))
{
byte[] result = new byte[resultStream.Length - 2];
resultStream.Position = 0;
resultStream.Read(result, 0, result.Length);
CanMoveNext = true;
data.name = Encoding.UTF8.GetString(result).Replace("Content-Disposition: form-data; name=\"", "").Replace("\"", "").Split(';')[0];
resultStream.Dispose();
resultStream = new MemoryStream();
}
else if (Encoding.UTF8.GetString(currentChunk).Contains("Content-Type"))
{
CanMoveNext = true;
data.type = 1;
resultStream.Dispose();
resultStream = new MemoryStream();
}
else if (CompareBytes(EndBoundary, currentChunk))
{
byte[] result = new byte[resultStream.Length - EndBoundary.Length - 2];
resultStream.Position = 0;
resultStream.Read(result, 0, result.Length);
data.datas = result;
resultStream.Dispose();
CanMoveNext = false;
}
}
}
return HttpListenerPostValueList;
}
catch (Exception ex)
{
return null;
}
}
#endregion <方法>
}
public class HttpListenerPostValue
{
public int type = 0;
public string name;
public byte[] datas;
}
}
3.下载例程
该例程演示了HttpListener、HttpWebRequest的应用,包括如何解析POST请求中Body的数据(multipart/form-data)、如何构造multipart/form-data; boundary=的ContentType等进行文件、参数上传等技巧:https://download.csdn.net/download/CGS_______/33070416
|