基于C#的软件大杂烩(5.1)——简介HTTP协议以及编写HTTP服务端
上一期我们介绍了使用TCP协议来建立流式传输实现实时的图像显示。我们也简单的提到了HTTP与TCP协议的优缺点。
本期我们简单的介绍一下HTTP并且使用C#制作一个HTTP助手来接收我们的HTTP消息。
HTTP简介
HTTP是超文本传输协议(Hypertext Transfer Protocol)的简称,既然是一种协议,HTTP分为客户端和服务端,顾名思义服务端是为客户端服务的。服务端不会主动发送请求,但是服务端可以响应客服端发出的请求。
客户端通过请求报文向服务端发送消息,服务端接收到请求报文后会使用响应报文对客户端进行响应,HTTP规定了请求报文和响应报文的格式。
HTTP请求报文如下所示

例如这个例子,请求方法是GET,请求路劲是http://192.168.137.1,版本是HTTP/1.1

200通常代表着响应成功。
其实关于HTTP还有好多好多内容,我们就简单的介绍一下HTTP的请求和响应机制,接着使用C#编写测试代码。
界面布局

还是简单的布置一下我们的界面,使用一个Teox来接收客户端发送的请求报文,下面设置一个我们的自定义响应文本。
右边使用Comox控件来存放电脑的可用IP地址,并且可以选择输入端口号。
设置波形显示的勾选框,方便后期可以从HTTP协议中解析波形。
设置详细信息的勾选框,可以选择显示详细信息还是显示简短的信息。
主要代码
private void LoadLocalIPv4Addresses()
{
try
{
// 获取本地主机名
string hostName = Dns.GetHostName();
// 获取主机名对应的IP地址列表
IPAddress[] ipAddresses = Dns.GetHostAddresses(hostName);
// 筛选IPv4地址并添加到ComboBox
foreach (IPAddress ipAddress in ipAddresses.Where(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork))
{
IPAddressChoose.Items.Add(ipAddress.ToString());
}
// 设置默认选择第一个IPv4地址
if (IPAddressChoose.Items.Count > 0)
{
IPAddressChoose.SelectedIndex = 0;
}
}
catch (Exception ex)
{
Messaox.Show($"错误: {ex.Message}", "错误", MessaoxButtons.OK, MessaxIcon.Error);
}
}
利用Dns.GetHostName的方法获得主机的可用IP地址,并将地址写入名为IPAddressChoose的Coox控件中
需要注意的是传入格式的问题IPAddresses是IPAddress类型的数据,我们需要将其转换为IPAddress类型传入IPAddressChoose控件的Text属性中。
private HttpListener httpListener = null;
private void CreateHttpListener()
{
try
{
httpListener = new HttpListener();
// 获取选择的 IP 地址和端口号
string selectedIpAddress = IPAddressChoose.SelectedItem.ToString();
string selectedPort = PortChoose.Text;
// 创建监听地址
string listenUrl = $"http://{selectedIpAddress}:{selectedPort}/";
// 创建 HttpListener 实例
httpListener.Prefixes.Add(listenUrl);
// 启动监听器
try
{
// 启动监听器
httpListener.Start();
IPAddressChoose.Enabled = true;
PortChoose.Enabled = true;
// 异步处理接收请求
Task.Run(async () =>
{
while (true)
{
// 等待请求连接
HttpListenerContext context = await httpListener.GetContextAsync();
// 处理请求
HandleHttpRequest(context);
}
});
}
catch (HttpListenerException ex)
{
// 输出错误信息或采取适当的处理措施
MessageBox.Show("访问端口失败\r\n如未启动管理员模式请使用管理员模式启动\r\n检查端口是否被占用可以尝试更换端口");
}
}
catch (Exception ex)
{
Messaox.Show($"Error: {ex.Mese}", "Error", MessxButtons.OK, Messacon.Error);
}
}
private void HandleHttpRequest(HttpListenerContext context)
{
// 获取请求对象
HttpListenerRequest request = context.Request;
// 获取请求的 URL
string url = request.Url.AbsoluteUri;
// 获取请求的 HTTP 方法(GET、POST 等)
string httpMethod = request.HttpMethod;
// 获取请求头
WebHeaderCollection headers = request.Headers as WebHeaderCollection;
// 获取请求的 IP 地址
string ipAddress = context.Request.RemoteEndPoint?.Address?.ToString();
// 读取请求正文
string requestBody;
using (System.IO.Stream body = request.InputStream)
using (System.IO.StreamReader reader = new System.IO.StreamReader(body, request.ContentEncoding))
{
requestBody = reader.ReadToEnd();
}
// 在这里处理请求正文
this.BeginInvoke(new Action(() =>
{
// 显示 IP 地址
if (!ChartShow.Checked)
{
Recive.AppendText("New Message:\r\n");
Recive.AppendText($"IP Address: {ipAddress}\r\n");
// 显示 URL
Recive.AppendText($"URL: {url}\r\n");
}
if (MoreDetile.Checked&&!ChartShow.Checked)
{
// 显示 HTTP 方法
Recive.AppendText($"HTTP Method: {httpMethod}\r\n");
// 显示请求头
Recive.AppendText($"Request Headers:\n{string.Join("\n", headers.AllKeys.Select(key => $"{key}: {headers[key]}"))}\r\n");
// 显示请求正文
Recive.AppendText($"Request Body:\n{requestBody}\r\n");
}
else
{
Dictionary keyValuePairs = ParseJsonRequestBody(requestBody);
// 在这里处理请求正文
this.BeginInvoke(new Action(() =>
{
// 打印键值对
foreach (var kvp in keyValuePairs)
{
if (double.TryParse(kvp.Value, out double doubleValue))
{
if (ChartShow.Checked)
{
// 在 Chart 中检查是否包含对应键名的 Serial
if (chart.Series.Any(series => series.Name == kvp.Key))
{
// 如果已经包含,将数据添加到对应的 Serial 中
chart.Series[kvp.Key].Points.AddXY(chart.Series[kvp.Key].Points.Count+1, double.Parse(kvp.Value));
}
else
{
// 如果不存在,新建对应键名的 Serial,并添加数据
Series newSeries = new Series(kvp.Key);
Random random = new Random();
Color randomColor = Color.FromArgb(random.Next(256), random.Next(256), random.Next(256));
// 新建 Series,并设置线条的属性
newSeries.Color = randomColor; // 设置颜色
newSeries.BorderWidth = 3; // 设置宽度
newSeries.ChartType = SeriesChartType.Spline;
newSeries.Points.AddY(double.Parse(kvp.Value));
chart.Series.Add(newSeries);
}
}
}
Recive.AppendText($"{kvp.Key}: {kvp.Value}\r\n");
}
}));
}
}));
// 构建响应内容
string responseString = Recall.Text;
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
// 发送响应
HttpListenerResponse response = context.Response;
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
}
接着初始化一个监听实例,根据我们选择的IP地址以及端口号创建HTTP监听,并通过异步的方式处理接收到的数据,将数据打印或者从中解析出波形显示在外面的页面上。


登录 或 注册 后才可以进行评论哦!