当前位置: 首页 > news >正文

Django+Nginx+uwsgi网站使用Channels+redis+daphne实现简单的多人在线聊天及消息存储功能

网站部署在华为云服务器上,Debian系统,使用Django+Nginx+uwsgi搭建。最终效果如下图所示。

一、响应逻辑顺序

1. 聊天页面请求

客户端请求/chat/(输入聊天室房间号界面)和/chat/room_name(某个聊天室页面)链接时,由Nginx转到Django由urls.py解析并返回相应页面,在返回的聊天室页面内置了javascript程序,请求建立wss:/ws/chat/room_name的websocket连接。

2. websocket连接请求

客户端向Nginx发送websocket连接请求,根据Ngnix配置文件location /ws {}中设置的反向代理,请求被转到本地的7001端口( http://127.0.0.1:7001),将由运行在该端口上的由daphne托管的asgi服务解析并响应(配置文件为myproject/asgi.py)。

3. asgi.py解析并响应

asgi.py中定义的application定义了websocket的解析规则,具体由/myproject/routing.py中的websocket_urlpatterns进行地址解析,通过Channels由myapp/comsumers.py进行异步信息处理并响应。

二、配置Channels和asgi

1. 安装Channels
sudo pip3 install channels
2. settings.py中添加应用并配置channels和asgi
INSTALLED_APPS = ['django.contrib.auth','django.contrib.admin', 'django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','channels','myapp',
]ASGI_APPLICATION = 'myproject.asgi.application'# Channels_Layers相关配置
CHANNEL_LAYERS = {'default': {'BACKEND': 'channels_redis.core.RedisChannelLayer','CONFIG': {"hosts": [('127.0.0.1', 6379)],},},
}# 配置认证后端
AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',
)

Django Channels利用 Redis 作为通道层来管理客户端和服务器之间的通信。当客户端通过 WebSocket 连接发送消息时,Django Channels 会使用 Redis 将消息分发到所有连接的客户端。Redis 充当消息代理,实时有效地处理消息的路由和传递。

ASGI_APPLICATION指向Django项目下的asgi.py文件中的application。

3.  配置asgi.py文件
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
django.setup()from django.core.asgi import get_asgi_application
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from myproject import routingsapplication = ProtocolTypeRouter({'http':get_asgi_application(),                          #支持http请求'websocket':AuthMiddlewareStack(URLRouter(routings.websocket_urlpatterns)  #支持webscoket请求),
})

此处django.setup()和DJANGO_SETTINGS_MODULE设置应放在导入模块前,否则容易出现如下报错: 

django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
Requested setting DEBUG, but settings are not configured. 
You must either define the environment variable DJANGO_SETTINGS_MODULE 
or call settings.configure() before accessing settings...

 WSGI和ASGI 的主要区别是同步VS异步,WSGI是同步的,每个请求必须等待前一个请求完成。而ASGI是异步的,可以同时处理多个请求。 WSGI主要用于HTTP协议,ASGI旨在支持WebSocket、HTTP2等协议。ASGI的主要特点是异步非阻塞,它能够更好地处理并发请求。

上述设置中websocket地址解析由Django项目下的routings.py完成,其功能与urls.py类似。

4. 配置routings.py
from django.urls import path
from myapp import consumerswebsocket_urlpatterns = [path(r'ws/chat/<str:room_name>/', consumers.ChatConsumer.as_asgi())
]

 myapp为新建的应用,其下的consumers.py文件定义了websocket的响应函数ChatConsumer。

5. 配置myapp/consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
from asgiref.sync import sync_to_async
from myapp.models import ChatMessageclass ChatConsumer(AsyncWebsocketConsumer):async def connect(self):self.room_name = self.scope["url_route"]["kwargs"].get("room_name") #获取传输的房间号if self.room_name:self.room_group_name = f"chat_{self.room_name}"# Join room groupawait self.channel_layer.group_add(self.room_group_name, self.channel_name)await self.accept()else:await self.close()async def disconnect(self, close_code):# Leave room groupawait self.channel_layer.group_discard(self.room_group_name, self.channel_name)# Receive message from WebSocketasync def receive(self, text_data):text_data_json = json.loads(text_data)message = text_data_json["message"]username = text_data_json["username"]#保存消息await self.save_message(username, self.room_name, message)# 向群组内的所有客户端发送消息,type为“chat_message"await self.channel_layer.group_send(self.room_group_name, {"type": "chat_message", "message": message,'username':username})# Receive message from room groupasync def chat_message(self, event):message = event["message"]username = event['username']# Send message to WebSocketawait self.send(text_data=json.dumps({"message": message,'username':username}))# 信息写入数据库@sync_to_async()def save_message(self, username, room, message):if len(message) !=0 :newmsg = ChatMessage.objects.create(username=username, room=room, content=message)newmsg.save()

文件中定义了websocket的连接,消息的接收、发送和存储,每条消息在发送给群组内的所有客户端前先存储到数据库。

三、消息存储

1. 配置myapp/models.py,用于消息存储
from django.db import modelsclass ChatMessage(models.Model):username = models.CharField(max_length=100,verbose_name='用户名')room = models.CharField(max_length=100)content = models.TextField(verbose_name='内容')create_time = models.DateTimeField(auto_now_add=True,verbose_name='写入时间')def __str__(self):return f"房间号:{self.room}--用户:{self.username}({self.content})"
2. 配置myapp/admin.py,便于在Django后台处理存储的消息
from django.contrib import admin# Register your models here.
from .models import ChatMessage
admin.site.register(ChatMessage)

 效果如下:

 四、安装redis并启动

1. 安装redis
sudo apt-get install redis-server

安装后redis-server会自动启动,可以使用sudo systemctl start/stop/restart/status redis.service来启动/停止/重启/查看服务器。

$sudo systemctl status redis.service ● redis-server.service - Advanced key-value storeLoaded: loaded (/lib/systemd/system/redis-server.service; enabled; vendor preset: enabled)Active: active (running) since Tue 2024-11-19 23:38:28 CST; 20h agoDocs: http://redis.io/documentation,man:redis-server(1)Main PID: 123767 (redis-server)Status: "Ready to accept connections"Tasks: 5 (limit: 2321)Memory: 7.2MCPU: 1min 36.022sCGroup: /system.slice/redis-server.service└─123767 /usr/bin/redis-server 127.0.0.1:6379

五、安装daphne,并启动asgi服务

1. 安装daphne

 Daphne 是 Django Channels 项目的一部分,专门用于为 Django 提供支持 WebSocket和 ASGI 协议的异步服务器。

sudo pip3 install daphne

启动asgi服务的命令如下,监听端口为7001。

daphne -p 7001 myproject.asgi:application

asgi服务的配置文件即为前面已经完成的asgi.py。

为了管理方便,将其做成系统服务开机启动。

2. 设置daphne.service服务

新建/etc/systemd/system/daphne.service文件

sudo nano /etc/systemd/system/daphne.service

内容如下: 

[Unit]
Description=Daphne Server
After=network.target[Service]
Type=exec
WorkingDirectory=/home/yislwll/Django/myproject
ExecStart=/usr/bin/daphne -p 7001 myproject.asgi:application
Restart=always
User=yislwll
Group=Yisl
Environment=PYTHONPATH=/home/yislwll/Django/myproject[Install]
WantedBy=multi-user.target

然后启动daphne服务:

sudo systemctl enable daphne.service
sudo systemctl start daphne.service

需要特别注意的是,修改consumers.py文件后一定要重启daphne服务,否则对websocket通讯内容的更改无法更新。

sudo systemctl restart daphne.service

 六、配置Nginx

根据响应逻辑,Ngnix应该对websocket的连接“wss://域名/ws/chat/room_name”做出响应,请求将被代理到本地的7001端口,由运行在该端口上由daphne托管的asgi服务解析并响应。

1. 配置/etc/nginx/nginx.conf

网站为https://连接,所以webscoket连接为wss://

	server {listen       443  ssl;server_name  xxxx.com;charset      utf-8;ssl_certificate /path/to/fullchain.pem;  # SSL证书的路径ssl_certificate_key /path/to/privkey.pem;  # 私钥的路径# SSL 配置ssl_session_timeout 1d;ssl_session_cache shared:MozSSL:10m;  # about 4000 sessionsssl_session_tickets off;# 指定加密套件ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers 'xxxxxxxxx';ssl_prefer_server_ciphers on;location / {#由django响应uwsgi_pass 127.0.0.1:8080;include uwsgi_params;include /etc/nginx/uwsgi_params;uwsgi_param UWSGI_SCRIPT iCourse.wsgi;uwsgi_param UWSGI_CHDIR /iCourse;index index.html index.htm;client_max_body_size 35m;index index.html index.htm;}location /ws {#wss协议由asgi服务响应proxy_http_version 1.1;proxy_set_header Host  $host;proxy_set_header X-Real-Ip $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Nginx-Proxy true;proxy_redirect off;client_max_body_size 10m;proxy_pass http://127.0.0.1:7001;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";proxy_connect_timeout 300s;proxy_read_timeout 300s;proxy_send_timeout 300s; }}
2. 重启Nginx服务
sudo systemctl restart nginx.service

七、客户端界面

1. 配置urls.py,响应客户端界面请求 
from myapp import views as channelsviewurlpatterns = [......path('chat/',channelsview.chat, name='webchat'),path('chat/<str:room_name>/', channelsview.chatroom, name='chatroom'),......
]

客户端页面请求将由myapp/views.py来处理。

2. 配置views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from .models import ChatMessage# Create your views here.
@login_required(login_url='/login/')
def chat(request):return render(request,"channels/chattingindex.html")@login_required(login_url='/login/')
def chatroom(request,room_name):username = request.session.get('username','游客')msgs = ChatMessage.objects.filter(room=room_name).order_by('create_time')[0:20]return render(request,"channels/chattingroom.html",{'room_name':room_name,'username':username, 'msgs':msgs})

在chatroom函数中,对当前聊天室历史消息的最近20条进行了查询,并由页面展示出来。

3. 聊天页面设计及通讯

chattingroom.html文件内容大致如下:

{% extends "newdesign/newbase.html" %}{% load django_bootstrap5 %}{% block mytitle %}<title>{{room_name}}号聊天室</title><style>.chat-window {max-width: 900px;height: 500px;overflow-y: scroll; /* 添加垂直滚动条 */margin: auto;background-color: #f1f1f1;border: 2px solid #09e3f7;border-radius: 5px;padding: 10px;}.chat-message {clear: both;overflow: hidden;margin-bottom: 10px;text-align: left;}.chat-message .message-content {border-radius: 5px;padding: 8px;max-width: 500px;float: left;clear: both;}.chat-message.right .message-content {background-color: #428bca;color: white;float: right;width:420px;}.chat-message.right .user-content {background-color: #f7e91d;border-radius:4px;color: black;float: right;width: auto;text-align: right;padding-left:10px;padding-right:10px;}.chat-message.left .message-content {background-color: #2ef3be;border-color: #ddd;float:left;width:420px;}.chat-message.left .user-content {background-color: #f7e91d;border-radius:4px;border-color: #ddd;float: left;width: auto;text-align: left;padding-left:8px;padding-right:8px;}</style>{% endblock %}{% block maincontent %} <div class="container"><div id="chat-record" class="chat-window">{% for m in msgs %}{% if m.username == request.user.username %}<div class="chat-message right"><div class="user-content">{{m.username}}</div><div class="message-content"><span>{{m.content}}</span></div></div><br>{% else %}<div class="chat-message left"><div class="user-content">{{m.username}}</div><div class="message-content"><span>{{m.content}}</span></div></div><br>{% endif %}{% endfor %}</div></div><br><div class="mx-auto px-auto" style="text-align: center;"><input id="chat-message-input" type="text" style="width:900px;" size="150"><br><br><input id="chat-message-submit" type="button" value="发送消息"></div>{{ room_name|json_script:"room-name" }}{{ username|json_script:"username" }}<script>window.onload = function() {var scrollableDiv = document.getElementById('chat-record');// 设置scrollTop使得滚动条向下翻scrollableDiv.scrollTop = scrollableDiv.scrollHeight;};const roomName = JSON.parse(document.getElementById('room-name').textContent);const username = JSON.parse(document.getElementById('username').textContent);const chatSocket = new WebSocket('wss://scybbd.com/ws/chat/' + roomName + '/');chatSocket.onmessage = function(e) {const data = JSON.parse(e.data);//data为收到的后端发出来的数据console.log(data);if (data['message']) {if(data['username'] == username){document.querySelector('#chat-record').innerHTML += ('<div class="chat-message right"><div class="user-content">' + data['username'] + '</div><div class="message-content"><span>' +data['message'] + '</span></div></div><br>');}else{document.querySelector('#chat-record').innerHTML += ('<div class="chat-message left"><div class="user-content">' + data['username'] + '</div><div class="message-content"><span>' + data['message'] + '</span></div></div><br>');}} else {alert('消息为空!')}var scrollableDiv = document.getElementById('chat-record');// 设置scrollTop使得滚动条向下翻scrollableDiv.scrollTop = scrollableDiv.scrollHeight;};chatSocket.onclose = function(e) {console.error('聊天端口非正常关闭!');};document.querySelector('#chat-message-input').focus();document.querySelector('#chat-message-input').onkeyup = function(e) {if (e.keyCode === 13) {  // enter, returndocument.querySelector('#chat-message-submit').click();}};document.querySelector('#chat-message-submit').onclick = function(e) {const messageInputDom = document.querySelector('#chat-message-input');const message = messageInputDom.value;chatSocket.send(JSON.stringify({'message': message,'username':username}));messageInputDom.value = '';};</script>
{% endblock %}

聊天界面比较简陋,客户端与服务器的wss://连接和通讯由页面中javacript脚本完成。

至此,一个简单的多人在线聊天的页面基本完成。

相关文章:

Django+Nginx+uwsgi网站使用Channels+redis+daphne实现简单的多人在线聊天及消息存储功能

网站部署在华为云服务器上&#xff0c;Debian系统&#xff0c;使用DjangoNginxuwsgi搭建。最终效果如下图所示。 一、响应逻辑顺序 1. 聊天页面请求 客户端请求/chat/&#xff08;输入聊天室房间号界面&#xff09;和/chat/room_name&#xff08;某个聊天室页面&#xff09;链…...

数据结构在二叉树Oj中利用子问题思路来解决问题

二叉树Oj题 获取二叉树的节点数获取二叉树的终端节点个数获取k层节点的个数获取二叉树的高度检测为value的元素是否存在判断两颗树是否相同判断是否是另一棵的子树反转二叉树判断一颗二叉树是否是平衡二叉树时间复杂度O(n*n)复杂度O(N) 二叉树的遍历判断是否是对称的二叉树二叉…...

华为openEuler考试真题演练(附答案)

【单选题】 以下关于互联网的描述&#xff0c;哪个选项是正确的? A:Nginx 在万维网中可以作为 ftp 服务器的反向代理&#xff0c;并与ftp服务器的数量--对应 B:Nginx 在互联网中可以作为 web服务器端&#xff0c;成为万维网的一个节点 C:互联网上的的资源需使用 Nginx进行七层…...

生成自签名证书并配置 HTTPS 使用自签名证书

生成自签名证书 1. 运行 OpenSSL 命令生成证书和私钥 在终端中输入以下命令&#xff0c;生成自签名证书和私钥文件&#xff1a; sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout self_signed.key -out self_signed.pem-x509&#xff1a;生成自签名证书。…...

物联网核心安全系列——智能汽车安全防护的重要性

汽车行业引入的智能硬件技术已经越来越多&#xff0c;早先设计者更多考虑到的是硬件成本和软件用户体验等因素&#xff0c;但随着国外两位技术人员成功实现远程控制汽车的视频曝出后&#xff0c;智能汽车安全便成为了一个热议话题。 汽车总线架构及原理比较复杂&#xff0c;日…...

数据库视图

数据库视图&#xff08;Database View&#xff09;是数据库中的虚拟表&#xff0c;其内容由查询定义&#xff0c;通常用来简化复杂的查询或提供安全访问数据。视图并不存储实际数据&#xff0c;而是将查询的结果集作为一个“虚拟表”呈现。用户通过查询视图&#xff0c;就可以看…...

从传统分析到智能问数,打造零门槛数据分析方案

众所周知&#xff0c;传统报表和自助分析工具存在使用门槛&#xff0c;且早期智能分析不够智能。随着AI技术发展&#xff0c;现有数据应用模式难以满足多样化、快速变化的需求&#xff0c;数据驱动、敏捷决策、精细运营成为了各大企业的新课题。 01企业数据应用挑战 业务人员的…...

java 设计模式 模板方法模式

模板方法模式&#xff08;Template Method Pattern&#xff09;是一种行为型设计模式&#xff0c;它在父类中定义一个算法的框架&#xff0c;允许子类在不改变算法结构的情况下重写算法的某些特定步骤。这种模式非常适合于那些有一定公共流程&#xff0c;但某些步骤需要子类定制…...

基于UDP和TCP实现回显服务器

目录 一. UDP 回显服务器 1. UDP Echo Server 2. UDP Echo Client 二. TCP 回显服务器 1. TCP Echo Server 2. TCP Echo Client 回显服务器 (Echo Server) 就是客户端发送什么样的请求, 服务器就返回什么样的响应, 没有任何的计算和处理逻辑. 一. UDP 回显服务器 1. UD…...

在 CentOS 系统上直接安装 MongoDB 4.0.25

文章目录 步骤 1&#xff1a;配置 MongoDB 官方源步骤 2&#xff1a;安装 MongoDB步骤 3&#xff1a;启动 MongoDB 服务步骤 4&#xff1a;验证安装步骤 5&#xff1a;可选配置注意事项 以下是在 CentOS 系统上直接安装 MongoDB 4.0.25 的详细步骤&#xff1a; 步骤 1&#x…...

Android和IOS的区别

一、系统区别 1、系统和框架的区别 &#xff08;1&#xff09;Android系统的底层建立在Linux系统之上&#xff1b;而ios基于UNIX系统 Android完全开放&#xff0c;iOS完全封源开发 &#xff08;2&#xff09;编程语言:Android的编程语言是Java和KotLin&#xff1b;而ios的则为O…...

数据库基础(MySQL)

1. 数据库基础 1.1 什么是数据库 存储数据用文件就可以了&#xff0c;为什么还要弄个数据库? 文件保存数据有以下几个缺点&#xff1a; 文件的安全性问题文件不利于数据查询和管理文件不利于存储海量数据文件在程序中控制不方便 数据库存储介质&#xff1a; 磁盘内存 为…...

Vue前端开发子组件向父组件传参

在父组件中&#xff0c;如果需要获取子组件中的数据&#xff0c;有两种方式&#xff0c;一种是在子组件中自定义事件&#xff0c;父组件绑定该事件&#xff0c;当触发自定义事件时&#xff0c;向父组件传入参数;另一种是先通过ref属性给子组件命名&#xff0c;然后在父组件中就…...

javaScript语法基础(函数,对象,常用类Array,String,Math和Date)

# 本文详细结束了JavaScript中函数、对象、常用类Array&#xff0c;String&#xff0c;Math和Date的用法。 一、函数 1、概述 将程序中多次要用到的代码块封装起来&#xff0c;就是函数。函数使代码块的重复使用更方便&#xff0c;且功能独立&#xff0c;便于维护。 2、函数的…...

WebStorm 2022.3.2/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理

WebStorm 2022.3.2/IntelliJ IDEA 2024.3出现elementUI提示未知 HTML 标记、组件引用爆红等问题处理 1. 标题识别elementUI组件爆红 这个原因是&#xff1a; 在官网说明里&#xff0c;才版本2024.1开始&#xff0c;默认启用的 Vue Language Server&#xff0c;但是在 Vue 2 项…...

k8s-NetworkPolicy

NetworkPolicy 是k8s中的网络策略可以限制pod以及namespace之间的访问流量 演示一下名称空间之间基于端口的访问限制 官方对networkpolicy的介绍 官方网址&#xff1a; 网络策略 |Kubernetes &#xff08;简体中文&#xff09; 一&#xff1a;创建NetworkPolicy vim…...

【C++】踏上C++学习之旅(九):深入“类和对象“世界,掌握编程的黄金法则(四)(包含四大默认成员函数的练习以及const对象)

文章目录 前言1. 实现Date类的构造函数2. 实现Date类的拷贝构造函数3. 实现Date类的赋值运算符重载4. 实现各Date对象之间的比较接口5. 实现Date对象的加减接口6. const成员7. 取地址及const取地址操作符重载 前言 在我们前面学习到了"类和对象"的四大默认成员函数(…...

C++——智能指针剖析

参考&#xff1a; 恋恋风辰官方博客 动态内存管理 - cppreference.com SRombauts/shared_ptr&#xff1a; 一个最小的 shared/unique_ptr 实现&#xff0c;用于处理 boost/std&#xff1a;&#xff1a;shared/unique_ptr 不可用的情况。 C智能指针_c 智能指针-CSDN博客 当…...

241119.LeetCode——383.赎金信

题目描述 给你两个字符串&#xff1a;ransomNote 和 magazine &#xff0c;判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以&#xff0c;返回 true &#xff1b;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1&#xff1a; 输…...

基于SSM的农家乐管理系统+论文示例参考

1.项目介绍 功能模块&#xff1a;管理员&#xff08;农家乐管理、美食信息管理、住宿信息管理、活动信息、用户管理、活动报名、论坛等&#xff09;&#xff0c;普通用户&#xff08;注册登录、活动报名、客房预订、用户评价、收藏管理、模拟支付等&#xff09;技术选型&#…...

用 Python 从零开始创建神经网络(九):反向传播(Backpropagation)(还在更新中。。。)

反向传播&#xff08;Backpropagation&#xff09; 引言1. 分类交叉熵损失导数&#xff08;Categorical Cross-Entropy loss derivative&#xff09;2. 分类交叉熵损失衍生代码实现3. Softmax激活导数&#xff08;Softmax activation derivative&#xff09;4. Softmax激活函数…...

Flink是如何实现 End-To-End Exactly-once的?

flink 如何实现端到端的 Exactly-once? 端到端包含 Source, Transformation,Sink 三部分的Exactly-once Source&#xff1a;支持数据的replay&#xff0c;如Kafka的offset。Transformation&#xff1a;借助于checkpointSink&#xff1a;Checkpoint 两阶段事务提交 两阶段提…...

【vulhub】nginx解析漏洞(nginx_parsing_vulnerability)

1. nginx解析漏洞原理 fastcgi 在处理’.php’文件时发现文件并不存在,这时 php.ini 配置文件中cgi.fix_pathinfo1 发挥作用,这项配置用于修复路径,如果当前路径不存在则采用上层路径 (1)由于 nginx.conf的配置导致 nginx把以’.php”结尾的文件交给 fastcgi 处理,为此可以构造…...

网络协议之邮件协议(SMTP、POP3与IMAP)

一、引言 在数字化时代&#xff0c;电子邮件已成为人们日常沟通和信息交流的重要工具。电子邮件系统的稳定运行离不开一系列网络协议的支撑&#xff0c;其中SMTP、POP3和IMAP是最为关键的三个协议。它们分别负责邮件的发送、接收和管理&#xff0c;共同构建了一个高效、稳定的…...

python学习笔记(3)运算符

Python 语言支持的运算符: Python 语言支持以下类型的运算符: 算术运算符 比较&#xff08;关系&#xff09;运算符 赋值运算符 逻辑运算符 位运算符 成员运算符 身份运算符 运算符优先级 接下来让我们一个个来学习Python的运算符。 Python算术运算符 运算符描述实例加 - 两…...

_FYAW智能显示控制仪表的简单使用_串口通信

一、简介 该仪表可以实时显示位移传感器的测量值&#xff0c;并可设定阈值等。先谈谈简单的使用方法&#xff0c;通过说明书&#xff0c;我们可以知道长按SET键可以进入参数选择状态&#xff0c;按“↑”“↓”可以选择该组参数的上一个或者下一个参数。 从参数一览中可以看到有…...

激光雷达定位初始化的另外一个方案 通过键盘按键移动当前位姿 (附python代码)

通常使用的是通过在 rviz 中点选指定初始化位置和方向来完成点云的初始化匹配。 但是这种粗略的初始化方法有时候可能不成功,因此需要使用准确的初始化方法,以更好的初始值进行无损检测配准。 为了提供更好的匹配初始值,我使用 Python 脚本获取键盘输入,并不断调整这个匹配…...

从0-1逐步搭建一个前端脚手架工具并发布到npm

前言 vue-cli 和 create-react-app 等 cli 脚手架工具用于快速搭建应用&#xff0c;无需手动配置复杂的构建环境。本文介绍如何使用 rollup 搭建一个脚手架工具。 脚手架工具的工作流程简言为&#xff1a;提供远端仓库各种模版 > 用户通过命令选择模版 > 拉取仓库代码 …...

河道水位流量一体化自动监测系统:航运安全的护航使者

在广袤的水域世界中&#xff0c;航运安全始终是至关重要的课题。而河道水位流量一体化自动监测系统的出现&#xff0c;如同一位强大的护航使者&#xff0c;为航运事业的稳定发展提供了坚实的保障。 水位传感器&#xff1a;负责实时监测河道的水位变化。这些传感器通常采用先进的…...

维护在线重做日志

学习目标 解释在线重做日志文件的目的概述在线重做日志文件的结构控制日志开关和检查点多路复用和维护在线重做日志文件使用OMF管理在线重做日志文件获取在线重做日志文件信息 在线重做日志文件提供了在数据库发生故障时重做事务的方法。 每个事务都同步写入重做日志缓冲区&a…...

网站系统建设申请报告/百度网盘下载官网

开发混合app上架应用市场&#xff0c;需要进行应用签名&#xff0c;但是申请签名如果没搞过&#xff0c;会特别麻烦&#xff0c;所以我自自己总结了一下申请的步骤&#xff0c;在此记录一下1.首先需要下载安装java环境即jdk&#xff0c;2.配置环境变量假设JDK安装在C:\Program …...

网络推广排名/关键词优化技巧

组建团队 人员培养 知识分享...

网站建设图标/指数函数图像及性质

看了一眼&#xff0c;上次更新距今2个月&#xff0c;看起来我好咕咕啊&#xff08;感叹&#xff09;&#xff0c;可是感觉这两个月也没闲着捏&#xff08;比赛&#xff0c;cf&#xff0c;期末等等&#xff0c;幸亏期末考延期了&#xff0c;我这被期末作业都整死了快&#xff09…...

做推广的免费的济宁网站有哪些/发帖子的网站

主要是解决在测试使用mongo db 时候&#xff0c;总是出现的MongoAuthenticationException 异常和 not authorized for query&#xff0c;not authorized on admin to execute command 等问题。 直接上测试步骤图拉。 我这个是先卸载了原来的mongo服务&#xff0c;然后删除我…...

新手怎样在手机上做电商/seo服务方案

&#xff08;《partner4java 讲述jBPM4》仅为技术储备 -- 本人并没有jBPM4实战方面丰富的经验&#xff1b;学习本内容最好有Hibernate的基础&#xff09; 代码下载地址&#xff1a;文章中贴出的代码可能有所改动&#xff0c;以下载地址为准http://download.csdn.net/detail/pa…...

自学网站平面设计/东莞网站推广行者seo08

这是悦乐书的第190次更新&#xff0c;第193篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第49题&#xff08;顺位题号是204&#xff09;。计算小于非负数n的素数的数量。例如&#xff1a; 输入&#xff1a;10 输出&#xff1a;4 说明&#xff1a;有4个素数小于…...