nginx配置websocket_django3,websocket,asgi,daphne,nginx 结合使用示例

这篇文章主要讲解在 django3 的项目中,如何使用 websocket

这是一个 代理IP 的小项目,当前为0.2版本,该版本分为三端,服务器端,代理IP端,用户端

可以做到在任意一台服务器和任意内网电脑上一键部署,一键启动,使该服务器通过内网机器为你提供代理IP服务。可以做到在服务器数量有限的情况下,部署更多的代理IP

该项目今后的发展方向是在手机上部署代理IP端,以获得更多的代理IP

当前环境为:

ubuntu 20.04python 3.8aiohttpasynciodjango 3.1daphnenginx

项目流程图:

ade7bf1b0dd7fda4079899b45bd5139e.png

看起来很简单的4个步骤,在技术选型上却想了很久,曾经想过轮询和消息队列的模型,都遇见一个无法绕过的问题:服务器和用户连接的这个进程,如何才能知道代理IP那边已经完成了任务?

后来突发奇想,能不能让TCP的连接不断开,有这个保证的话,可能会想到一些办法。我就上百度去搜,发现这个技术已经有了,就是websocket,这名字我是见过的,在我爬取招聘网站信息提取关键词的时候,我还以为那是socket的一种别称,就没注意过它……

这里,我主要先讲一下

websocket 如何与采用 asgi 协议的 django3.X 项目结合食用.

如果asgi.py文件还不会写,那么请先看最下面的  【asgi.py 文件的编写】,那个不是我的原创,就放在后面了

websocket 的使用在 django3 里面有3个参数,他们分别是:(scope, receive, send)

async def application(scope, receive, send):    """    var connection = new WebSocket('ws://127.0.0.1:8000/abc')        scope:  详细如下        {'type': 'websocket',        'path': '/abc',        'raw_path': b'/abc',        'headers': [(b'host', b'127.0.0.1:8000'), (b'upgrade', b'WebSocket'), (b'connection', b'Upgrade'),                    (b'sec-websocket-version', b'13'), (b'sec-websocket-key', b'2viLa4ZBnF2953ARONVITw=='),                    (b'accept', b'*/*'), (b'accept-encoding', b'gzip, deflate'), (b'user-agent',                                b'Python/3.8 aiohttp/3.6.2')],        'query_string': b'',        'client': ['127.0.0.1', 47220],        'server': ['127.0.0.1', 8000],        'subprotocols': [],        'asgi': {'version': '3.0'}}    receive:  详细如下                tasks=1>>        

  send:

  """

从上面的注解可以看出:

scope 是一个详细信息的字典,其中包含了(协议类型,请求路径,请求头,查询字符串,客户端IP,服务端IP和其他的东西)

receive 是一个接收消息的对象,很明显可以看到其中包含了一条管道对象,而这条管道,我理解为就是收发消息的通道

send 是一个发送消息的对象,里面也包含了这条管道。

每一个建立的 websocket 都拥有独一无二的 这三个参数,也就是说,这三个参数合在一起,就相当于是我们建立的 websocket,

这也是当初困扰我的问题,如何在一个websocket里面,向另一个websocket发送消息,其实我们只需要拿到另一个websocket的 send 参数就可以了。

接下来,我们只要在连接建立之后,将这三个参数存入一个全局变量中,或是数据库中,我们就可以在任何地方,任何时候,调用任意一个websocket,以实现我们由服务端,主动向客户端发送消息的需求

# 这里展示一下,在代理IP与服务器建立的websocket连接中,调用客户与服务器连接的send对象,向客户发送消息pmip_dict = {}async def bypmip(scope, receive, send):    """    服务器端逻辑:将代理IP的IP做键,websocket对象作值,存入pmip_dict字典,如果该键已经存在,则拒绝连接,断开连接时删除该键值对    循环等待接收代理IP服务器的消息(这个消息包含爬虫返回的信息在内),再将该消息转发给提出此需求的客户    """    while True:        event = await receive()        if event['type'] == 'websocket.connect':            # 初次建立连接时,会进入这个分支            ip = scope['client'][0]            if not pmip_dict.get(ip, ''):                # 将代理IP的IP做键,整个websocket作为值,存入字典                pmip_dict[ip] = [scope, receive, send]                await send({'type': 'websocket.accept'})            else:                await send({'type': 'websocket.no'})                        elif event['type'] == 'websocket.receive':            # 连接建立以后,接收到的消息会进入这个分支            # 判断这条消息是给哪个客户的,进行选择发送            # print(event)            # >>> {'type': 'websocket.receive', 'bytes': b'user=127.0.0.1:40766,text=\nspan role="presentation" cm-text="	" style="box-sizing: border-box;font-family: var(--monospace);display: inline-block;">                               html>\n\n\n…………}            message = event['bytes']            # >>> b'user=127.0.0.1:40766,text=\n\n\n\n…………            user = re.search(rb'user=(?P.*?),text', message, re.S).group('IP').decode()            text = re.search(rb',text=(?P.*)',message,re.S).group('text')            if target_send := clien_dict.get(user,None)[-1]:                # 【这里就是在代理IP与服务器的websocket连接中,调用客户与服务器的send对象,向客户发送消息】                await target_send({'type': 'websocket.send', 'bytes': text})        elif event['type'] == 'websocket.disconnect':            # 断开连接时,会进入这个分支            try:                del pmip_dict[ip]            except Exception as e:                pass            print('断开连接')            break

asgi.py 文件的编写(这里是百度上找的)

import osfrom django.core.asgi import get_asgi_application# 【【【【记得改】】】】from [你的项目名字].websocket import websocket_application# 【【【【记得改】】】】os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myasgi.settings')django_application = get_asgi_application()async def application(scope, receive, send):    if scope['type'] == 'http':        # http 请求的入口        await django_application(scope, receive, send)    elif scope['type'] == 'websocket':        # websocket 请求的入口        await websocket_application(scope, receive, send)    else:        raise NotImplementedError(f"Unknown scope type {scope['type']}")

接着在 asgi.py 文件的同级目录下,建立一个 websocket.py文件,并在里面创建一个函数 websocket_application,这个函数里就是整个websocket 完整逻辑

async def websocket_application(scope, receive, send):    # 主函数    # 这里面是你自己的逻辑,怎么写都行        # 我这里是鉴别来者身份,并执行对应函数    result = await authentication(scope)    await method_dict[result](scope, receive, send)

用 daphne 启动项目

# 进入项目目录下daphne [你的项目名字].asgi:application

基于 nginx 的 daphne(百度找的,亲测可用)

修改nginx 的配置文件 /etc/nginx/sites-enabled/default,添加或修改如下信息

upstream socket {    ip_hash;    server 127.0.0.1:8000 fail_timeout=0;}# 上面的IP端口自定义,就是daphne运行的端口server {    listen 80 default_server;    listen [::]:80 default_server;    ...    location / {        proxy_pass http://socket;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection "upgrade";    }    ...}

启动daphne

# 在项目的 mannerge.py 同级目录下执行daphne [你的项目名字].asgi:application

到这里,整个项目就启动了,欢迎点赞分享

欢迎关注我的微信公众号:不定期更新一些python相关的文章

116d6998696d5c5827e1bebab1975434.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值