www.zhblog.net

web页面通过websocket获取客户端本地已安装的软件列表

需求:web页面通过js获取客户端本地已安装的程序软件列表,兼容目前主流浏览器。

js获取本地数据由于安全问题,在主流浏览器中是禁止的。ie6、7、8、9可以通过如 ActiveX、flash、java applet技术达到目的,但在主流浏览器中这些都被淘汰了。网上大多推荐使用websocket,因为html5原生支持。

环境:web页面html5 websocket;服务端python。

web页面很简单,发送ws请求(可以传递数据作为验证使用),接收到的本地已安装的程序软件列表直接输出到页面

function sendInfo() {
    var username = 'abc';
    var password = '123';

    // 打开连接    
    var ws = new WebSocket("ws://localhost:6789");

    // 发送数据    
    ws.onopen = function () {
        // 使用send()方法发送数据        
        ws.send(username+'-'+password);
    };

    // 接收数据    
    ws.onmessage = function (evt) {
        var received_msg = evt.data;
        var obj = JSON.parse(received_msg);
        $.each(obj.result, function (i, n) {
            document.writeln(n + '<br/>');
        });
        // 作为一个好习惯,在接收完数据后就关闭连接,这样可以减少服务器的负担        
        ws.close();
    };

    // 关闭连接后的事件    
    ws.onclose = function () {
    };
}
sendInfo();


服务端python使用websocket_server, 读取注册表获取已安装的软件列表使用winreg。 

import logging
from websocket_server import WebsocketServer
import sys
import winreg
import json
import os

def new_client(client, server):
    print('new client...', client)

def client_left(client, server):
    print('client left...')

def message_back(client, server, message):
    # 这里的message参数就是客户端传进来的内容    
    print('revice clien...', message)
    # 这里可以对message进行各种处理    
    # 将处理后的数据再返回给客户端    
    server.send_message(client, json.dumps({'result': list(get_reg())}))

def get_reg():
    # 32位程序和64位程序注册表
    reg_path_32 = r'SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'    
    reg_path_64 = r'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall'    
    # 32位程序和64位程序都需要读取
    reg_paths = (reg_path_32, reg_path_64)
    result = set()
    for reg_path in reg_paths:
        registry_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path, 0, winreg.KEY_READ)
        info = winreg.QueryInfoKey(registry_key)
        for i in range(info[0]):
            try:
                sub_key = winreg.EnumKey(registry_key, i)
                key = reg_path + '\{}'.format(sub_key)
                info_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, key, 0, winreg.KEY_READ)
                # print('-------', winreg.QueryValueEx(info_key, 'DisplayName'))                
                result.add(winreg.QueryValueEx(info_key, 'DisplayName')[0])
            except Exception:
                pass        
        winreg.CloseKey(registry_key)
    return result


def start():
    """添加到注册表,开机自启动"""
    reg_path = r'Software\\Microsoft\\Windows\\CurrentVersion\\Run'    
    registry_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, reg_path, 0, winreg.KEY_SET_VALUE)
    winreg.SetValueEx(registry_key, 'softwarelistapp', 0, winreg.REG_SZ, os.path.join(os.getcwd(), 'softplus.exe'))

def ws_listen():
    server = WebsocketServer(6789)
    server.set_fn_new_client(new_client)
    server.set_fn_client_left(client_left)
    server.set_fn_message_received(message_back)
    server.run_forever()

if __name__ == '__main__':
    ws_listen()


以上方式在主流浏览器中可以运行,但现在需要兼容ie8和ie9,不想换实现方式,所有用flash插件实现ie8的websocket,再通过上面代码实现功能。

web页面使用web-socket-js插件来实现ie8的websocket:

<script src="jquery.min.js"></script>
<script type="text/javascript" src="web-socket-js-master/swfobject.js"></script>
<script type="text/javascript" src="web-socket-js-master/web_socket.js"></script>

function sendInfoByIE(){
    WEB_SOCKET_SWF_LOCATION = "web-socket-js-master/WebSocketMain.swf";

    // Write your code in the same way as for native WebSocket:    
      var ws = new WebSocket("ws://localhost:6789");
      ws.onopen = function() {
        ws.send("Hello");  // Sends a message.      
      };
      ws.onmessage = function(e) {
        // Receives a message.        
        var received_msg = e.data;
        var obj = JSON.parse(received_msg);
        $.each(obj.result, function (i, n) {
            document.writeln(n + '<br/>');
        });      
        ws.close();
      };
      ws.onclose = function() {

      };
}

var win = window;
var doc = win.document;
var input = doc.createElement ("input");

var ie = (function (){
    //"!win.ActiveXObject" is evaluated to true in IE11    
    if (win.ActiveXObject === undefined) return null;
    if (!win.XMLHttpRequest) return 6;
    if (!doc.querySelector) return 7;
    if (!doc.addEventListener) return 8;
    if (!win.atob) return 9;    
    if (!input.dataset) return 10;
    return 11;
})();

if(ie<10){
    sendInfoByIE();
}else{
    sendInfo();
}


服务端python使用标准socketserver即可:

class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):

    def handle(self):
        policy_file = """            
            <cross-domain-policy>                
                <allow-access-from domain="*" to-ports="*" />            
            </cross-domain-policy>        
        """        
        self.request.sendall(policy_file.encode('utf-8'))


class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
    pass

def socket_listen():
    host, port = "localhost", 843    
    server = ThreadedTCPServer((host, port), ThreadedTCPRequestHandler)
    # with server:    
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one    
    # more thread for each request    
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates    
    # server_thread.daemon = True    
    server_thread.start()
    # server.shutdown()


因为websocket与socketserver同时用,所以socketserver使用线程方式异步运行。

展开阅读全文

评论

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 心情