事情起源:公司视频播放一直是采用的嵌入浏览器组件实现视频的预览回放等功能。这种实现方式要求客户使用IE浏览器。

最近上线项目使用Html 5开发,要求IE11。项目中使用了视频播放功能,如果全部升级到IE11问题多,工作量大。

存在的主要问题:

有些系统开发较早,不能在IE11上运行。

部分客户电脑配置低还在使用XP。因为视频播放插件要求IE浏览器,所以支持H5的chrome,firefox等浏览器又不符合要求。

修改项目兼容低版本浏览器那是不可能的,只能修改视频播放插件。

1、视频插件改为 应用程序 安装到客户计算机,使用浏览器自定义协议启动。这样解决了浏览器兼容问题,几乎所有浏览器都支持自定义协议。

测试用例:注册表写入以下内容就可以启动 d:\myapp.exe

Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\myapp]
@="URL:AutoHotKey myapp Protocol"
"URL Protocol"=""
[HKEY_CLASSES_ROOT\myapp\DefaultIcon]
@="myapp.exe,1"
[HKEY_CLASSES_ROOT\myapp\shell]
[HKEY_CLASSES_ROOT\myapp\shell\open]
[HKEY_CLASSES_ROOT\myapp\shell\open\command]
@="\"d:\\myapp.exe\" \"%1\""

javascript 点击启动myapp.exe

function LaunchApp() {
try {

window.location = 'myapp://,start';

}
catch (ex) {
errMsg = "启动 myapp 报错.\n\n";
alert(errMsg);
}
return;
};

2、如何判断用户有没安装视频应用呢??

网上搜索了一下,看着比较靠谱的:

https://www.cnblogs.com/tangjiao/p/9646855.html

这个实现方案是有缺陷,在chrome浏览器通过计时器和当前窗体失去焦点来判段。

计时器设置时间短路了,程序在配置低的电脑上会失败。

计时器设置时间长了,chrome上切换tab页就失去焦点,认为已经安装。

通过观察百度云盘的运行方式,得到启发。百度云盘也是采用了自定义协议。启动yundetectservice.exe 监听10000端口,

猜测web页面和yundetectservice.exe进行了通信。yundetectservice.exe启动成功会通知web页面。

3、采用 websocket 实现,视频应用启动的时候监听某端口等待 web页面连接,如果一定时间内连接成功就认为已经安装了插件。

web页面websocket连接的例子网上比较多。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Test</title>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
var noSupportMessage = "Your browser cannot support WebSocket!";
var ws; function appendMessage(message) {
$('body').append(message);
} function connectSocketServer() {
var support = "MozWebSocket" in window ? 'MozWebSocket' : ("WebSocket" in window ? 'WebSocket' : null); if (support == null) {
appendMessage("* " + noSupportMessage + "<br/>");
return;
} appendMessage("* Connecting to server ..<br/>");
// create a new websocket and connect
ws = new window[support]('ws://localhost:12345/'); // when data is comming from the server, this metod is called
ws.onmessage = function (evt) {
appendMessage("# " + evt.data + "<br />");
}; // when the connection is established, this method is called
ws.onopen = function () {
appendMessage('* Connection open<br/>');
$('#messageInput').attr("disabled", "");
$('#sendButton').attr("disabled", "");
$('#connectButton').attr("disabled", "disabled");
$('#disconnectButton').attr("disabled", "");
}; // when the connection is closed, this method is called
ws.onclose = function () {
appendMessage('* Connection closed<br/>');
$('#messageInput').attr("disabled", "disabled");
$('#sendButton').attr("disabled", "disabled");
$('#connectButton').attr("disabled", "");
$('#disconnectButton').attr("disabled", "disabled");
}
} function sendMessage() {
if (ws) {
var messageBox = document.getElementById('messageInput');
ws.send(messageBox.value);
messageBox.value = "";
}
} function disconnectWebSocket() {
if (ws) {
ws.close();
}
} function connectWebSocket() {
connectSocketServer();
} window.onload = function () {
$('#messageInput').attr("disabled", "disabled");
$('#sendButton').attr("disabled", "disabled");
$('#disconnectButton').attr("disabled", "disabled");
} </script>
</head>
<body>
<input type="button" id="connectButton" value="Connect" onclick="connectWebSocket()"/> <input type="button" id="disconnectButton" value="Disconnect" onclick="disconnectWebSocket()"/> <input type="text" id="messageInput" /> <input type="button" id="sendButton" value="Send" onclick="sendMessage()"/> <br />
</body>
</html>

实现websocket服务也有很多方法。

开源的有,SuperWebSocket,Fleck,WebSocketListener,websocket-sharp 等。

DotNet 高版本自带了System.Net.WebSockets;

因为功能简单,仅仅是接受连接请求,所以采用dontnet自带的,不用引入多余的类库。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks; namespace TestServer
{
class Program
{
static void Main(string[] args)
{
RunEchoServer().Wait();
}
private static async Task RunEchoServer()
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:12345/");
listener.Start();
Console.WriteLine("Started");
while (true)
{
HttpListenerContext context = listener.GetContext();
//
if (!context.Request.IsWebSocketRequest)
{
context.Response.Close();
continue;
}
//
Console.WriteLine("Accepted");
//
var wsContext = await context.AcceptWebSocketAsync(null);
var webSocket = wsContext.WebSocket;
//
byte[] buffer = new byte[];
WebSocketReceiveResult received = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None); while (received.MessageType != WebSocketMessageType.Close)
{ Console.WriteLine($"Echoing {received.Count} bytes received in a {received.MessageType} message; Fin={received.EndOfMessage}");
// Echo anything we receive
await webSocket.SendAsync(new ArraySegment<byte>(buffer, , received.Count), received.MessageType, received.EndOfMessage, CancellationToken.None); received = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
} await webSocket.CloseAsync(received.CloseStatus.Value, received.CloseStatusDescription, CancellationToken.None); webSocket.Dispose();
Console.WriteLine("Finished");
}
}
}
}

至此,通过自定义协议和websocket 解决了视频插件的问题。

采用自定义协议代替OCX组件的更多相关文章

  1. OCX组件

    转自:http://blog.sina.com.cn/s/blog_4ca9ceef0100ixzb.html 一.OCX(OLE Control Extensio,OLE Object Linkin ...

  2. 利用Netty构建自定义协议的通信

    在复杂的网络世界中,各种应用之间通信需要依赖各种各样的协议,比如:HTTP,Telnet,FTP,SMTP等等. 在开发过程中,有时候我们需要构建一些适应自己业务的应用层协议,Netty作为一个非常优 ...

  3. C#综合揭秘——通过修改注册表建立Windows自定义协议

    引言 本文主要介绍注册表的概念与其相关根项的功能,以及浏览器如何通过连接调用自定义协议并与客户端进行数据通信.文中讲及如何通过C#程序.手动修改.安装项目等不同方式对注册表进行修改.其中通过安装项目对 ...

  4. java-cef系列视频第四集:自定义协议

    上一集我们介绍了如何为java-cef添加flashplayer支持. 本视频介绍java-cef中的自定义协议 本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 中国大陆许可协议进行许可.

  5. 在网络7层协议中,如果想使用UDP协议达到TCP协议的效果,可以在哪层做文章?(QQ 为什么采用 UDP 协议,而不采用 TCP 协议实现?)

    为了解决这题,可以具体看看下面这个讨论. 解灵运工程师 185 人赞同 某次架构师大会上那个58同城做即时通信的人说:原因是因为当时没有epoll这种可以支持成千上万tcp并发连接的技术,所以他们使用 ...

  6. 【转】C#综合揭秘——通过修改注册表建立Windows自定义协议

    引言 本文主要介绍注册表的概念与其相关根项的功能,以及浏览器如何通过连接调用自定义协议并与客户端进行数据通信.文中讲及如何通过C#程序.手动修改.安装项目等不同方式对注册表进行修改.其中通过安装项目对 ...

  7. 各种非标232,485协议,自定义协议转modbus协议模块定制开发,各种流量计协议转modbus,

    工业现场经常会碰到通过485或者232采集各类仪表数据,但是很多早期的仪表和设备不支持标准modbus协议,而是采用自定义的协议,这些协议数据由plc或者dcs系统来实现采集,不仅费时麻烦,而且不方便 ...

  8. 移动网络应用开发中,使用 HTTP 协议比起使用 socket 实现基于 TCP 的自定义协议有哪些优势?

    HTTP 是应用层协议,TCP 是传输层协议(位于应用层之下),放在一起类比并不合适.不过猜测楼主是想对比 “标准 HTTP 协议” 还是 “自定义的协议(基于 TCP Socket)” . 一般来说 ...

  9. 通过修改注册表建立Windows自定义协议

    引言 本文主要介绍注册表的概念与其相关根项的功能,以及浏览器如何通过连接调用自定义协议并与客户端进行数据通信.文中讲及如何通过C#程序.手动修改.安装项目等不同方式对注册表进行修改.其中通过安装项目对 ...

随机推荐

  1. Python3.7 练习题(三) 将指定目录下的图片进行批量尺寸大小处理

    # 将指定目录下的图片进行批量尺寸大小处理 #修改图片尺寸 导入Image os 快捷键 alt+enter import os from PIL import Image def process_i ...

  2. Go爬去以太坊的价格数据

    package main import ( "encoding/json" "errors" "fmt" "io/ioutil&q ...

  3. .NET数据采集

    public string GetHttpData(string Url) { string sException = null; string sRslt = null; WebResponse o ...

  4. 【笔记】 laravel 的路由

    路由简介 : 请求对应着路由,将用户的请求转发给相应的程序进行处理 建立URL与程序之间的映射 Laravel中的请求类型:get.post.put.patch.delete   Route::get ...

  5. 用python给邮箱发邮件,问题,以及解决方法。

    模版 import smtplib #导入相关模块 from email.mime.text import MIMEText from email.utils import formataddr de ...

  6. JAVA for(i = 0; i<a.length; i++) 解析

    下列 System.out.printf 语句输出的结果是什么? Char a[]={„a‟,‟b‟,‟c‟,‟d‟,‟e‟}; For(i=0; i<=a.length/2; i++) { c ...

  7. vc6.0问题

    1.VC6不自动提示函数的参数 是工程中的.ncb文件有问题,把这个文件删除就正常了. 2.设置代码提示快捷键 Tools-->定制-->弹出框,按照下图设置  3.报错 (1)ident ...

  8. Taskctl安装及配置Kettle插件

    服务端安装 从官网下载服务端安装包(含字符客户端/代理组件) 1.环境变量设置 在fedora的终端下,输入sudo vi /etc/profile,将以下语句添加至文末 export TASKCTL ...

  9. ketlle windows下的安装(最基本)

    ketlle基本介绍 kettle是纯java开发,开源的etl工具.可以在Linux.windows.unix中运行.有图形界面,也有命令脚本还可以二次开发. kettle其实是以前的叫法,现在官方 ...

  10. (转)Unity_什么是Draw Call? 什么是Batch?

    開發遊戲時,一定被時時提醒要減少 Draw Call,當然UNITY也不例外,打開Game Window裡的 Stats,可以看到 Draw Call 與 Batched 的數字.但到底甚麼是 Dra ...