编程实战:自己编写HTTP服务器(系列8:流水输出和无刷新动态显示)

系列入口:编程实战:自己编写HTTP服务器(系列1:概述和应答)-CSDN博客

        本文是精华,前面所有的铺垫只是为了实现页面数据实时刷新啊!

目录

一、我们想要的实时系统监控界面是什么

二、原理

2.1 流水式页面

2.2 滚动到底部

2.3 动态更新

2.4 重新加载页面

2.4 更多技巧

三、动态更新的一些提示


一、我们想要的实时系统监控界面是什么

        理想的实时系统的监控界面是一个监控屏幕,上面各种数字和指示灯闪烁。但是程序只能像流水一样吐出数据,所以前端界面需要做很多事情来解决这个问题。

        方案不过是“推”或者“拉”。“推”就是服务端主动发送,客户端等待接收,程序不算简单。“拉”就是客户端定时请求,因为是客户端完全控制,程序比“推”简单。

        但是我们希望更简单一些,因为没有前端帮忙,最好一切都在我们的程序里解决。办法不难,需要利用HTTP和HTML的几个小特性。

二、原理

2.1 流水式页面

        大部分情况下web页面都是一个完整的页面,有HTTP请求头、有body(就是html页面内容),请求头包含一个“Content-Length”指示内容长度。

        但是这不是绝对的,如果没有“Content-Length”,浏览器仍然可以正确处理页面,只不过浏览器会以连接结束作为数据结束的标志(因此不可能使用http1.1的保持连接)。

        浏览器处理这种页面的时候(其实也包括所有页面),总是尽快显示内容,不用等到内容结束,能理解多少就显示多少(所以有时候你会看到页面先是显示一些东西,然后布局变化了,可能变化几次,最后才稳定下来)。

        所以如果不发送页面结束给浏览器(页面结束是“”),不断吐出新内容,浏览器会不停显示的。

        这种方式足以显示日志这种流水文件了。前面介绍的执行shell命令处理输出就是这种方式。

2.2 滚动到底部

        浏览器不会自动滚动到底部,因此需要嵌入一段JavaScript脚本来让浏览器滚动到底部。

        代码在应答对象里面:

		void AppendBodyHtmlScroll()//添加HTML滚动
		{
			m_body += "\r\n";
		}

        浏览器遇到这种脚本块就会立即执行。当然,代码中需要立即执行Flash()来把应答发送到浏览器。

2.3 动态更新

        流水式页面不是我们最终的目标,我们最终的目标是不刷新页面的情况下更新数据,让浏览器变成一个显示面板。

        更新数据首先要知道更新的数据在哪里,一般就用html元素的id来识别,这意味着你需要先学习一下怎么用记事本手撸HTML页面。如果你输出的内容元素的id已经知道了,那么用一行脚本来更新数据就很容易了:

        这个代码很简单,但要注意,里面用到了CScriptEncode::Encode(data),功能是把不符合规则的字符替换掉,很显然,data被放在双引号中,双引号和回车换行都是要转义的:

	//编码为脚本
	class CScriptEncode
	{
	public:
		static string Encode(string const & str)
		{
			string ret = "";
			ret.reserve(str.size() * 2);
			for (string::size_type i = 0; i < str.size(); ++i)
			{
				if ('\"' == str[i])ret += "\\\"";
				else if ('\n' == str[i])ret += "\\n";
				else if ('\r' == str[i])ret += "\\r";
				else ret += str[i];
			}
			return ret;
		}
	};

         用代码生成代码必须理解这种转义再转义。

        现在,我们仍然使用流水式页面,但是输出的只是更新数据的脚本,这样,页面不会重新加载,但数据却活动起来了。

2.4 重新加载页面

        浏览器不能支持无限大的页面,因为浏览器把所有数据都放在内存里,用过的也不敢扔掉(谁知道你后面会不会调用呢),所以时间长了整个电脑都会被拖死。

        因此要定时重新加载。重新加载当然不能让用户手动点击,只要吐出一行脚本就可以了:

m_respond.AppendBody("");

        至于何时重新加载就更简单了,比如连续输出一分钟后输出一个这个,然后结束页面。浏览器会重新发起一个连接。隔几分钟重新加载一次用户应该没什么意见。

2.4 更多技巧

        完整页面也可以实现定时刷新,不过这就属于纯粹的前端技术了。用C++输出脚本太麻烦?可以写成文件啊,读文件进来啊。不过,这样会增加程序的不确定性,C++程序员应该不喜欢。

三、动态更新的一些提示

        动态更新需要知道页面元素的ID,可以按照固定的规则生成ID,程序里应该保持旧数据的一份拷贝,通过比较来针对有差异的数据输出脚本,无差异的就不用输出了。

        要确保页面元素确实存在,不然更新到不存在的元素会触发异常,这样用户的感觉就很不好了。

(这里是结束,而且是整个系列的结束)

你可能感兴趣的:(C++嵌入式HTTP服务器,http,服务器,网络协议,嵌入式,流水式页面,动态更新)