代码发布项目(二)——django实现websocket(使用channels)、基于channels实现群聊功能、gojs插件、paramiko模块

一、django实现websocket

django默认是不支持websocket,只支持http协议

在django中如果想要基于websocket开发项目 你需要安装模块:channles
    pip3 install channels==2.3
    版本不要使用最新的,如果安装最新的可能会自动把你的django版本升级到最新版
    对应的解释器环境建议使用3.6(官网的说法:3.5可能有问题,3.7可能也有问题...具体原因没有给解释)

    channels模块内部已经帮我们封装好了
        握手/加密/解密

面试点:
注意:不是所有的服务端都支持websocket
    django
        -默认不支持
        -但是有第三方的模块:channles来实现

    flask
        -默认不支持
        -但是也有第三方的模块:geventwebsocket

    tronado
        -默认支持

创建django项目测试channels模块

1.需要在配置文件中注册channels应用

INSTALLED_APPS = [
    # 1.需要先注册channels
    ‘channels‘
]

2.还需要在配置文件配置以下参数

# ‘与项目名同名的文件夹名.routing文件名.文件内的变量名application
ASGI_APPLICATION = ‘channels_demo.routing.application‘

3.创建routing.py文件(和settings.py同级),文件内容如下

from channels.routing import ProtocolTypeRouter,URLRouter

application = ProtocolTypeRouter({
    ‘websocket‘:URLRouter([
        # 路由与视图函数对应关系
    ])
})

注意配置完成后,django就会即支持http协议也支持websocket协议

强调

正常的http协议还是按照之前的写法 在urls中写路由与视图函数对应关系,正常的访问页面还是需要在urls中设置路径
而针对websocket协议则在当前文件内书写路由与视图函数对应关系,这个设置的路径在前端验证是否支持websocket使用

在routing文件中书写路由与视图函数对应关系

application = ProtocolTypeRouter({
    ‘websocket‘:URLRouter([
        url(r‘^chat/‘,consumers.ChatConsumer)
    ])
})

在项目根目录创建consumer.py文件用来专门处理websocket请求的视图函数

from channels.generic.websocket import WebsocketConsumer

class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self, message):
        """
        客户端发来链接请求之后就会自动触发
        """
    def websocket_receive(self, message):
        """
        客户端向服务端发送消息就会自动触发      message包括前端发送的消息
        """
    def websocket_disconnect(self, message):
        """
        客户端主动断开链接之后自动触发
        """

二、基于channels实现多人聊天室

http协议
    index                    index函数
    浏览器发送请求即可访问,设置url路径访问

websocket协议
    chat                    ChatConsumer类 内部有三个方法
    通过前端创建new WebScoket对象才能访问

后端

# 该文件内是专门用来写处理websocket请求的视图函数

from channels.generic.websocket import WebsocketConsumer
from channels.exceptions import StopConsumer

consumer_object_list = []

class ChatConsumer(WebsocketConsumer):
    def websocket_connect(self, message):
        """
        客户端发来链接请求之后就会自动触发
        """
        self.accept()  # 向服务端发送加密字符串,在前一章中讲的shankhands中的加密
        # self就是每一个客户端对象
        # 链接成功 我就将当前对象放入全局的列表中
        consumer_object_list.append(self)

    def websocket_receive(self, message):
        """
        客户端向服务端发送消息就会自动触发
        """
        print(message)     #接收客户端传递的信息

        # 给列表中所有的对象都发送消息,给客户端返回信息用send,传递信息用text_data
        for obj in consumer_object_list:
            obj.send(text_data=message.get(‘text‘))

    def websocket_disconnect(self, message):
        """
        客户端主动断开链接之后自动触发
        """
        print(‘断开链接了‘)
        # 服务端断开链接 就去列表中删除对应的客户端对象
        consumer_object_list.remove(self)
        raise StopConsumer   #停止消费

前端

<script>
    // 验证服务端是否支持websocket
    var ws = new WebSocket(‘ws://127.0.0.1:8000/chat/‘);
    //1.握手环节,连接成功自动触发,访问页面成功就会触发
    ws.onopen=function(){
        alert(‘验证成功‘)
    };
    // 2.客户端给服务端发送消息
    function sendMsg() {
        ws.send($(‘#d1‘).val())  // 将用户输入的内容发送给后端
    }
    // 3.接收服务端消息 会自动触发
    ws.onmessage = function (event) {  // event是数据对象 真正的数据在data属性内
        {#alert(event.data)  // 服务端返回的真实数据#}
        // 将消息渲染到html页面上
        var pEle = $(‘<p>‘);
        pEle.text(event.data);
        $(‘#content‘).append(pEle)

    };
    // 4.断开链接
    function closeLink() {
        ws.close()
    }
</script>

总结:

后端三个方法

websocket_connect
websocket_receive
websocket_disconnect

前端四个方法

var ws = new WebSocket(‘ws://127.0.0.1:8000/chat/‘);
ws.onopen
ws.send()
ws.onmessage
ws.close()

上述的群聊功能是我们自己临时想出来的 并不是真正的处理方式

要想实现完美的群聊功能需要借助于channel-layers

三、gojs插件

是一个前端组件,可以动态的创建各种流程图、图表...

基本使用

1.先用div占据页面一块内容,然后在该div内部操作图表

<div id="myDiagramDiv" style="width:500px; height:350px; background-color: #DAE4E4;"></div>
<script src="go.js"></script>
<script>
  var $ = go.GraphObject.make;
  // 第一步:创建图表
  var myDiagram = $(go.Diagram, "myDiagramDiv"); // 创建图表,用于在页面上画图
  // 第二步:创建一个节点,内容为jason
  var node = $(go.Node, $(go.TextBlock, {text: "jason"}));
  // 第三步:将节点添加到图表中
  myDiagram.add(node)
</script>

比较重要概念

  • TextBlock 创建文本
  • Shap 图形
  • Node 节点(将文本与图形结合)
  • Link 箭头

TextBlock

<div id="myDiagramDiv" style="width:500px; height:350px; background-color: #DAE4E4;"></div>
<script src="go.js"></script>
<script>
    var $ = go.GraphObject.make;
    // 第一步:创建图表
    var myDiagram = $(go.Diagram, "myDiagramDiv"); // 创建图表,用于在页面上画图
    var node1 = $(go.Node, $(go.TextBlock, {text: "jason"}));
    myDiagram.add(node1);

    var node2 = $(go.Node, $(go.TextBlock, {text: "jason", stroke: ‘red‘}));
    myDiagram.add(node2);

    var node3 = $(go.Node, $(go.TextBlock, {text: "jason", background: ‘lightblue‘}));
    myDiagram.add(node3);
</script>

Shap

gojs只引入go.js默认展示的图形比较少,你如果想展示其他图形,需要再引入Fugures.js

<div id="myDiagramDiv" style="width:500px; height:350px; background-color: #DAE4E4;"></div>
<script src="go.js"></script>
<script src="Figures.js"></script>
<script>
    var $ = go.GraphObject.make;
    // 第一步:创建图表
    var myDiagram = $(go.Diagram, "myDiagramDiv"); // 创建图表,用于在页面上画图
    var node1 = $(go.Node,
        $(go.Shape, {figure: "Ellipse", width: 40, height: 40})
    );
     myDiagram.add(node1);
     var node2 = $(go.Node,
        $(go.Shape, {figure: "RoundedRectangle", width: 40, height: 40, fill: ‘green‘,stroke:‘red‘})
    );
    myDiagram.add(node2);
    var node3 = $(go.Node,
        $(go.Shape, {figure: "Rectangle", width: 40, height: 40, fill: null})
    );
    myDiagram.add(node3);
    var node5 = $(go.Node,
        $(go.Shape, {figure: "Club", width: 40, height: 40, fill: ‘red‘})
    );
    myDiagram.add(node5);
</script>

Node 节点

<div id="myDiagramDiv" style="width:500px; height:350px; background-color: #DAE4E4;"></div>
<script src="js/go.js"></script>
<script src="js/Figures.js"></script>
<script>
    var $ = go.GraphObject.make;
    // 第一步:创建图表
    var myDiagram = $(go.Diagram, "myDiagramDiv"); // 创建图表,用于在页面上画图

    var node1 = $(go.Node,
         "Vertical",  // 垂直方向
        {
            background: ‘yellow‘,
            padding: 8
        },
        $(go.Shape, {figure: "Ellipse", width: 40, height: 40,fill:null}),
        $(go.TextBlock, {text: "jason"})
    );
    myDiagram.add(node1);

    var node2 = $(go.Node,
        "Horizontal",  // 水平方向
        {
            background: ‘white‘,
            padding: 5
        },
        $(go.Shape, {figure: "RoundedRectangle", width: 40, height: 40}),
        $(go.TextBlock, {text: "jason"})
    );
    myDiagram.add(node2);

    var node3 = $(go.Node,
        "Auto",  // 居中
        $(go.Shape, {figure: "Ellipse", width: 80, height: 80, background: ‘green‘, fill: ‘red‘}),
        $(go.TextBlock, {text: "jason"})
    );
    myDiagram.add(node3);
</script>

Link 箭头

流程图必备

<div id="myDiagramDiv" style="width:500px; min-height:450px; background-color: #DAE4E4;"></div>
    <script src="js/go-debug.js"></script>
    <script>
        var $ = go.GraphObject.make;

        var myDiagram = $(go.Diagram, "myDiagramDiv",
            {layout: $(go.TreeLayout, {angle: 0})}
        ); // 创建图表,用于在页面上画图

        var startNode = $(go.Node, "Auto",
            $(go.Shape, {figure: "Ellipse", width: 40, height: 40, fill: ‘#79C900‘, stroke: ‘#79C900‘}),
            $(go.TextBlock, {text: ‘开始‘, stroke: ‘white‘})
        );
        myDiagram.add(startNode);

        var downloadNode = $(go.Node, "Auto",
            $(go.Shape, {figure: "RoundedRectangle", height: 40, fill: ‘red‘, stroke: ‘#79C900‘}),
            $(go.TextBlock, {text: ‘下载代码‘, stroke: ‘white‘})
        );
        myDiagram.add(downloadNode);

        var startToDownloadLink = $(go.Link,
            {fromNode: startNode, toNode: downloadNode},
            $(go.Shape, {strokeWidth: 1}),
            $(go.Shape, {toArrow: "OpenTriangle", fill: null, strokeWidth: 1})
        );
        myDiagram.add(startToDownloadLink);
    </script>

如何结合后端动态生成  (后台传递数据)

拷贝使用即可

<div id="diagramDiv" style="width:100%; min-height:450px; background-color: #DAE4E4;"></div>
    <script src="js/go.js"></script>
    <script>
        var $ = go.GraphObject.make;
        var diagram = $(go.Diagram, "diagramDiv",{
            layout: $(go.TreeLayout, {
                angle: 0,
                nodeSpacing: 20,
                layerSpacing: 70
            })
        });

        diagram.nodeTemplate = $(go.Node, "Auto",
            $(go.Shape, {
                figure: "RoundedRectangle",
                fill: ‘yellow‘,
                stroke: ‘yellow‘
            }, new go.Binding("figure", "figure"), new go.Binding("fill", "color"), new go.Binding("stroke", "color")),
            $(go.TextBlock, {margin: 8}, new go.Binding("text", "text"))
        );

        diagram.linkTemplate = $(go.Link,
            {routing: go.Link.Orthogonal},
            $(go.Shape, {stroke: ‘yellow‘}, new go.Binding(‘stroke‘, ‘link_color‘)),
            $(go.Shape, {toArrow: "OpenTriangle", stroke: ‘yellow‘}, new go.Binding(‘stroke‘, ‘link_color‘))
        );
        var nodeDataArray = [
            {key: "start", text: ‘开始‘, figure: ‘Ellipse‘, color: "lightgreen"},
            {key: "download", parent: ‘start‘, text: ‘下载代码‘, color: "lightgreen", link_text: ‘执行中...‘},
            {key: "compile", parent: ‘download‘, text: ‘本地编译‘, color: "lightgreen"},
            {key: "zip", parent: ‘compile‘, text: ‘打包‘, color: "red", link_color: ‘red‘},
            {key: "c1", text: ‘服务器1‘, parent: "zip"},
            {key: "c11", text: ‘服务重启‘, parent: "c1"},
            {key: "c2", text: ‘服务器2‘, parent: "zip"},
            {key: "c21", text: ‘服务重启‘, parent: "c2"},
            {key: "c3", text: ‘服务器3‘, parent: "zip"},
            {key: "c31", text: ‘服务重启‘, parent: "c3"}
        ];
        diagram.model = new go.TreeModel(nodeDataArray);

        // 动态控制节点颜色变化
        /*
        var node = diagram.model.findNodeDataForKey("zip");
        diagram.model.setDataProperty(node, "color", "lightgreen");
        */
    </script>

默认所有的页面都有水印,如何除去水印

修改go.js文件中的源码,查找一个字符串7eba17a4ca3b1a8346

先注释

/*a.Cr=b.Z[Wa("7eba17a4ca3b1a8346")][Wa("78a118b7")](b.Z,Zk,4,4);*/

添加新内容

a.kr=function(){return true};

四、paramiko模块

通过ssh远程连接服务器并执行想要命令类似于Xshell

安装

pip install paramiko

使用

paramiko模块支持上面两种连接服务器的方式:

1.用户名和密码连接服务器

2.公钥私钥连接服务器

支持输入命令行

# 用户名和密码的方式
import paramiko

# 创建ssh对象
ssh = paramiko.SSHClient()
# 允许链接不在know_hosts文件中主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# 链接服务器
ssh.connect(hostname=‘172.16.219.168‘,port=22,username=‘root‘,password=‘jason123‘)

# 执行命令
stdin, stdout, stderr = ssh.exec_command(‘ip a‘)

# 获取结果
res = stdout.read()  # 基于网络传输 该结果是一个bytes类型
print(res.decode(‘utf-8‘))

# 断开链接
ssh.close()

# 公钥私钥方式
# 首先你要产生你自己的公钥和私钥  然后将你的公钥上传到服务器保存  之后就可以通过私钥来链接
"""
mac本
ssh-keygen -t rsa

ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]

cat ~/.ssh/id_rsa
"""

# # 公钥和私钥(先讲公钥保存到服务器上)
# import paramiko
#
# # 读取本地私钥
# private_key = paramiko.RSAKey.from_private_key_file(‘a.txt‘)
#
# # 创建SSH对象
# ssh = paramiko.SSHClient()
# # 允许连接不在know_hosts文件中的主机
# ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# # 连接服务器
# ssh.connect(hostname=‘172.16.219.168‘, port=22, username=‘root‘, pkey=private_key)
#
# # 执行命令
# stdin, stdout, stderr = ssh.exec_command(‘ls /‘)
# # 获取命令结果
# result = stdout.read()
# print(result.decode(‘utf-8‘))
# # 关闭连接
# ssh.close()

进行上传下载文件

# 用户名密码方式
# import paramiko
#
# # 用户名和密码
# transport = paramiko.Transport((‘172.16.219.168‘, 22))
# transport.connect(username=‘root‘, password=‘jason123‘)
#
# sftp = paramiko.SFTPClient.from_transport(transport)
#
# # 上传文件
# # sftp.put("a.txt", ‘/data/tmp.txt‘)  # 注意上传文件到远程某个文件下 文件必须存在
#
# # 下载文件
# sftp.get(‘/data/tmp.txt‘, ‘hahahha.txt‘)  # 将远程文件下载到本地并重新命令
# transport.close()

# 公钥私钥方式
#
# import paramiko
# private_key = paramiko.RSAKey.from_private_key_file(‘a.txt‘)
# transport = paramiko.Transport((‘172.16.219.168‘, 22))
# transport.connect(username=‘root‘, pkey=private_key)
# sftp = paramiko.SFTPClient.from_transport(transport)
# # 将location.py 上传至服务器 /tmp/test.py
# sftp.put(‘/tmp/location.py‘, ‘/tmp/test.py‘)
#
# # 将remove_path 下载到本地 local_path
# sftp.get(‘remove_path‘, ‘local_path‘)
# transport.close()

疑问点:如果我想链接服务器执行多条命令并且还想上传下载文件,那么你所能看到的一般做法都是执行一次命令创建一次链接

我们要实现在一个链接上即可以执行命令又可以上传下载文件

我们封装成一个类,类的内部有一系列的方法,并且这些方法都可以在同一个链接下执行多次

import paramiko

class SSHProxy(object):
    def __init__(self, hostname, port, username, password):
        self.hostname = hostname
        self.port = port
        self.username = username
        self.password = password
        self.transport = None

    def open(self):  # 给对象赋值一个上传下载文件对象连接
        self.transport = paramiko.Transport((self.hostname, self.port))
        self.transport.connect(username=self.username, password=self.password)

    def command(self, cmd):  # 正常执行命令的连接  至此对象内容就既有执行命令的连接又有上传下载链接
        ssh = paramiko.SSHClient()
        ssh._transport = self.transport

        stdin, stdout, stderr = ssh.exec_command(cmd)
        result = stdout.read()
        return result

    def upload(self, local_path, remote_path):
        sftp = paramiko.SFTPClient.from_transport(self.transport)
        sftp.put(local_path, remote_path)
        sftp.close()

    def close(self):
        self.transport.close()

    def __enter__(self):
        print(‘with开始‘)
        self.open()
        return self  # 该方法返回什么 with ... as 后面就拿到什么

    def __exit__(self, exc_type, exc_val, exc_tb):
        print(‘with结束‘)
        self.close()

if __name__ == ‘__main__‘:
    # obj = SSHProxy(hostname=‘172.16.219.168‘,port=22,username=‘root‘,password=‘jason123‘)
    # # 生成对象之后必须要先执行open方法
    # obj.open()
    # # 你就可以无限制的执行命令或者上传下载文件
    # obj.command(‘ls /‘)
    # obj.command(‘df‘)
    # obj.upload(‘a.txt‘,‘/data/tmp.txt‘)
    # # 断开链接
    # obj.close()
    """
    文件操作
    f = open()
    ...
    f.close()

    with上下文管理
    """
    obj = SSHProxy(hostname=‘172.16.219.168‘,port=22,username=‘root‘,password=‘jason123‘)

    with obj as ssh:  # 默认不支持  对象执行with会自动触发内部的__enter__方法
        print(‘with内部代码‘)
    # with上下文执行完毕之后 会自动触发__exit__方法

原文地址:https://www.cnblogs.com/wangcuican/p/12333643.html

时间: 2024-10-09 11:24:55

代码发布项目(二)——django实现websocket(使用channels)、基于channels实现群聊功能、gojs插件、paramiko模块的相关文章

代码发布系统二

服务端如何给客户端推送消息 轮询(效率低.基本不用) """ 让客户端浏览器定时朝服务端发送请求数据的请求(比如每隔5s一次) 不足之处 消息延迟明显 消耗资源 """ 长轮询(兼容性好.使用较多) """ 服务端给每一个第一次来链接的客户端浏览器创建一个队列,之后客户端浏览器通过ajax朝各自的队列索要数据,如果没有数据会阻塞但是不会一直阻塞(pending),用了timeout加异常处理经过30s自动回去然后再次

django实现websocket,gojs,paramiko模块

django如何实现websocket django默认是不支持websocket的,只支持http协议 """ 在django中如果想要基于websocket开发项目 你需要安装模块:channles pip3 install channels==2.3 版本不要使用最新的,如果安装最新的可能会自动把你的django版本升级到最新版 对应的解释器环境建议使用3.6(官网的说法:3.5可能有问题,3.7可能也有问题...具体原因没有给解释) channels模块内部已经帮我们

代码发布项目

代码发布概述图 如何解决当服务器特别多的时候,从同一个地方下载数据会出现压力过大的时刻(上传者只有一个,下载者却有很多歌,上传者压力太大) 采用比特流技术 将所有的人都变成既可以是上传者也可以是下载者 项目的概述: 利用modelform实现服务器表的增删改查 模板的基础作为模板的html文件上一般情况下,都应该定义在三个区域css区,html区和js区 针对服务器添加数据的功能,需要对提交的数据进行数据校验,还需要展示提示的信息,当模型字段非常多的时候前端页面展示代码量书写会很多,如何解决这样

代码发布项目(三)——python操作git、代码发布流程(服务器管理、项目管理)

一.python如何操作git 如果你想用python代码操作git需要下载一个模块 安装 pip install gitpython 基本使用 # 从远处仓库下载代码到本地 import os from git.repo import Repo # 创建本地存储地址,没有会自动创建文件 download_path = os.path.join('jason','NB') # 从远程仓库下载代码 Repo.clone_from('https://github.com/DominicJi/Teac

ASP.NET Web Deploy 发布项目二次开发发布编译出错原因

原先的ASP.NET 转换为 Web Deploy 项目后, 将所有的.CS文件打成一个包, 页面aspx文件保留, 项目开发人员拿到之后, 进行build, 开发没有问题, 但是publish WebSite的时候, 会出错. 错误:  Publication (web): 未将对象引用设置到对象的实例. 没有任何其他相关信息 , 打开aspnet_compiler.exe 的errorstack 选项后, 发现报错堆栈: error ASPRUNTIME: 未将对象引用设置到对象的实例. [

代码发布平台前戏

单纯做后端的话,可以用FastAPI框架 1.服务端主动给客户端推送消息 截至目前为止,我们所写的web项目基本都是基于HTTP协议的 HTTP协议有四大特性:无链接(我请求 你响应 我俩没关系了 直接断开链接) 基于HTTP协议实现服务端主动给客户端推送消息好像有点麻烦--- 我们都经历过,浏览器打开一个网站不动,网站过一会儿自动弹出消息 再比如网页版本的微信和qq,我们所有人创建一个群聊,所有人加入群聊之后都不动 我朝群中发送一个消息,你们所有人的页面上都会出现我发送的消息 如何实现服务端主

Flask 实现 WebSocket 通讯---群聊和私聊

一.WebSocket介绍 WebSocket是一种在单个TCP连接实现了服务端和客户端进行双向文本或二进制数据通信的一种通信的协议. WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据.在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输. 一次请求 - 服务器收到请求 开始和客户端握手 - 保持长连接 - 数据实时 - 连接永远保持 优点:长连接 并且不影响 收发请求 缺点:连接保

使用daphne部署django channles websocket 项目

前言:最近写了一个项目,有部分功能使用django channles websocket写的,使用的链接是wss:// 或者 ws:// ,到真实在uwsgi+nginx部署时,发现wss:// 或者 ws://不可用了,后来查了比较多时间,尝试过修改nginx配置文件,尝试过修改uwsgi配置文件,尝试过使用gunicorn部署,都没有解决此问题.最终发现需要多启用一个进程daphne,使用daphne启动django channles websocket对应功能进程,问题得到解决. 1.增加

代码发布系统三

django基于channels完成群聊功能 后端框架不一定默认支持websocket 三步走前期配置 """ http协议还是走 urls.py 与 views.py /index/ index 浏览器地址栏输入网址即可 websocket协议走routing.py 与 consumers.py /chat/ ChatConsumer 借助于js内置对象new WebSocket('ws://127.0.0.1:8080/chat/') """