上一期我们介绍了使用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监听,并通过异步的方式处理接收到的数据,将数据打印或者从中解析出波形显示在外面的页面上。

嘉立创PCB
全部评论 默认 最新
已折叠部分评论 展开
没有更多啦~