使用websockets和RESTful通信

要实时订阅RESTful服务端资源ac_status的状态,你需要使用WebSocket或者Server-Sent Events(SSE)。这两种技术都可以让服务器向客户端推送更新。

使用WebSocket协议:使服务端向客户端发送通知,客户端可实时接收空调状态(模拟空调)

使用RESTful 架构http协议:使客户端向服务端发送POST请求,更改空调状态(模拟相关控制空调的车载APP)

一、以下是使用WebSocket的示例:

服务端代码如下: 

import asyncio
import json
import threading
import websockets
from flask import Flask, request

app = Flask(__name__)

# 假设空调的初始状态  8000 change status   and   50000 notify status
ac_status = {
    'on': True,
    'temperature': 22
}

clients = set()

@app.route('/ac/status', methods=['GET'])
def get_ac_status():
    return ac_status

@app.route('/ac/on', methods=['POST'])
def turn_on_ac():
    print("---------turn_on_ac-----")
    # ac_status['on'] = True
    if ac_status['on']:
     print("air already open")   
    else:
        print("False---->True")
        ac_status['on'] = True
        # notify_clients()
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        loop.run_until_complete(notify_clients())
        loop.close()
    return ac_status

@app.route('/ac/off', methods=['POST'])
def turn_off_ac():
    print("---------turn_off_ac-----")
    ac_status['on'] = False
    # notify_clients()
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(notify_clients())
    loop.close()
    print("turn off ac_status====",ac_status)
    return ac_status

@app.route('/ac/setTemperature', methods=['POST'])
def set_ac_temperature():
    temperature = request.args.get('temp')
    if temperature:
        ac_status['temperature'] = int(temperature)
    # notify_clients()
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    loop.run_until_complete(notify_clients())
    loop.close()
    return ac_status

    
async def notify_clients():
    print("--------notify_clients-------")
    if clients:
        message = json.dumps(ac_status)
        await asyncio.wait([client.send(message) for client in clients])
    print(ac_status)

async def server(websocket, path):
    print("server")
    clients.add(websocket)
    if clients:
         print("clients exit")
         await notify_clients()
    else :
         print("clients no exit !!!")
    try:
        await websocket.recv()
    finally:
        clients.remove(websocket)

async def auto_change_ac_status():
    print("auto_change_ac_status")
    while True:
        print("sleep")
        await asyncio.sleep(3)  # 等待10秒
        if ac_status['on']:
            print("True---->False")
            ac_status['on'] = False
            await notify_clients()
        else:
            print("False---->True")
            ac_status['on'] = True
            await notify_clients()
           
def run_flask_app():
    app.run(host='0.0.0.0', port=8000)

# start_server = websockets.serve(server, "localhost", 5000)
start_server = websockets.serve(server, "0.0.0.0", 5000)

if __name__ == '__main__':
    
    asyncio.get_event_loop().run_until_complete(start_server)
    #开启 此处服务端会每隔3s自动更改空调状态
    # asyncio.ensure_future(auto_change_ac_status())
    flask_thread = threading.Thread(target=run_flask_app)
    flask_thread.start()
    asyncio.get_event_loop().run_forever()
   

在这个示例中,我们创建了一个WebSocket服务器,它监听localhost:5000。当有新的客户端连接时,我们将它添加到clients集合中。当有客户端断开连接时,我们将它从clients集合中移除。

我们还添加了一个notify_clients函数,当空调状态改变时,它会通知所有连接的客户端。

注意,这个示例使用了asyncio库,这是Python 3.4引入的一个异步IO库。如果你使用的是Python 2.x,你可能需要使用其他的异步IO库,比如Twisted。

另外,如果你的服务器只绑定到 localhost(即只监听 127.0.0.1),那么它将只能从同一台机器上访问。如果你想要从其他机器访问,你需要将服务器绑定到所有可用的网络接口,例如 0.0.0.0

客户端一(模拟空调控制器):

要实现实时通知,你需要在客户端和服务端都使用WebSocket。服务端已经使用了WebSocket,而客户端可以使用C++的websocket库,如cpprestsdk


#include <cpprest/ws_client.h>
#include <cpprest/json.h>
using namespace std;
using namespace utility;
using namespace web;
using namespace web::websockets::client;
using namespace concurrency::streams;

int main()
{
    websocket_callback_client client;
    client.connect(U("ws://192.168.48.129:5000/")).wait();

    client.set_message_handler([&](websocket_incoming_message msg) {
        auto response = msg.extract_string().get();
        auto jsonResponse = web::json::value::parse(response);
        auto status = jsonResponse[U("on")].as_bool();
        auto temperature = jsonResponse[U("temperature")].as_integer();
        std::cout << "Received status: " << status << ", temperature: " << temperature << std::endl;
    });
    
    // 阻塞主线程,防止退出
    std::string line;
    std::getline(std::cin, line);

    return 0;
}


这个客户端连接到服务端的WebSocket服务,并设置一个消息处理函数,该函数在接收到消息时被调用。消息被解析为JSON,然后提取出状态和温度,并打印出来。

请注意,这个客户端会一直运行,直到你手动停止它。如果你希望它在接收到消息后自动关闭,你需要在消息处理函数中添加一些逻辑来关闭WebSocket连接。

客户端二(模拟车载APP): 

(1)以下是使用cpprest库的C++示例:

#include <cpprest/http_client.h>
#include <cpprest/filestream.h>
#include <cpprest/json.h>
using namespace utility;
using namespace web;
using namespace web::http;
using namespace web::http::client;
using namespace concurrency::streams;

int main()
{
    http_client client(U("http://192.168.48.129:8000/"));

    // 打开空调
    http_request request(methods::POST);
    request.set_request_uri(U("ac/on"));
    client.request(request).get();

    // 关闭空调
    request = http_request(methods::POST);
    request.set_request_uri(U("ac/off"));
    client.request(request).get();

    // 设置空调温度
    request = http_request(methods::POST);
    request.set_request_uri(U("ac/setTemperature?temp=25"));
    client.request(request).get();

    return 0;
}

(2)使用Python的requests库来发送HTTP POST请求。以下是如何使用requests库来发送POST请求的示例:

import requests

# 关闭空调
print("--------关闭空调-------")
response = requests.post('http://192.168.48.129:8000/ac/off')
print(response.text)


#服务器返回的是JSON,使用如下
# 关闭空调
# print("--------关闭空调-------")
# response = requests.post('http://localhost:5000/ac/off')
# print(response.json())

# # 打开空调
# print("--------打开空调-------")
# response = requests.post('http://localhost:5000/ac/on')
# print(response.json())

# # 设置空调温度
# print("--------设置空调温度-------")
# response = requests.post('http://localhost:5000/ac/setTemperature', params={'temp': 25})
# print(response.json())

二、代码所需软件包的安装:

服务端依赖

1、安装websockets库

pip install websockets 或
sudo apt-get install libwebsocketpp-dev

2、安装flask

pip install flask 或
pip install flask -i https://pypi.python.org/simple
//上面安装还是不成功 可以升级pip后重试
pip install --upgrade pip

3、安装Python3 

(1)在Linux上,你可以通过包管理器来安装Python 3。例如,在Ubuntu上,你可以通过以下命令来安装Python 3:

sudo apt-get update
sudo apt-get install python3

(2)python命令默认指向Python 3,你可以创建一个符号链接。首先,你需要找到Python 3的路径,可以通过which python3命令来找到。然后,你可以使用sudo ln -s /path/to/python3 /usr/bin/python命令来创建一个符号链接。

注意:在执行ln -s命令时,你需要替换/path/to/python3为实际的Python 3路径。

例如,如果你的Python 3路径是/usr/bin/python3,你可以使用以下命令:

sudo ln -s /usr/bin/python3 /usr/bin/python

然后检查Python版本,它应该显示Python 3的版本。你可以使用以下命令:

python --version

:如果/usr/bin/python已经存在,并且是一个文件,而不是一个符号链接。这通常是因为你的系统已经安装了Python 2。

  • 首先,你需要确定Python 2的路径。你可以通过which python命令来找到。

  • 然后,你可以使用sudo mv命令来将Python 2的路径重命名。例如,如果你的Python 2路径是/usr/bin/python,你可以使用以下命令:

    sudo mv /usr/bin/python /usr/bin/python2
  • 最后,你可以使用sudo ln -s命令来创建一个指向Python 3的符号链接。例如,如果你的Python 3路径是/usr/bin/python3,你可以使用以下命令:

    sudo ln -s /usr/bin/python3 /usr/bin/python

    这样,你就可以通过python命令来运行Python 3了。

 客户端一依赖

1、安装cpprestsdk库

(1)cpprestsdk库是一个跨平台的C++ REST库,它可以用于构建基于REST的服务和客户端。以下是安装cpprestsdk的步骤:

 方法一:在Ubuntu或Debian上,你可以使用以下命令安装cpprestsdk

sudo apt-get install libcpprest-dev

 方法二:通过源代码编译

  • 从GitHub克隆cpprestsdk的源代码:

    git clone https://github.com/Microsoft/cpprestsdk.git
  • 进入cpprestsdk的目录,并创建一个构建目录:

    cd cpprestsdk
    mkdir build
    cd build
  • 使用CMake生成构建文件:

    cmake ..
  • 编译和安装cpprestsdk

    make
    sudo make install

(2)查看是否安装cpprestsdk库

在Linux上,你可以使用pkg-config工具来查看是否安装了cpprestsdk。在终端中输入以下命令:

pkg-config --modversion libcpprest

 如果cpprestsdk已经安装,那么这个命令将返回cpprestsdk的版本号。如果没有安装,那么这个命令将返回一个错误。

2、安装 Boost, OpenSSL, ZLib 和 CppUnit

(1)安装:

sudo apt-get update
sudo apt-get install libboost-all-dev libssl-dev libz-dev cppunit

 (2)使用:

        如果你在使用 CMake 来构建你的项目,你可以在你的 CMakeLists.txt 文件中添加以下代码:

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "path/to/cpprestsdk/share/cmake")
find_package(cpprestsdk REQUIRED)

add_executable(your_project your_project.cpp)

target_link_libraries(your_project PRIVATE cpprest)

        如下所示添加到CMakeLists.txt 文件中:

客户端二依赖:

安装requests库。你可以使用以下命令来安装: 

pip install requests

三、结果展示

四、代码相关知识

1、服务端

服务端包括 WebSocket服务器Flask应用两个服务。Flask应用需要在一个HTTP服务器上运行,而WebSocket服务器则不需要。 

(1)WebSocket协议的使用参考链接:我们来谈谈websocket_websocket 线程_RNGWGzZs的博客-CSDN博客文章浏览阅读998次。一、初始WebSocket"你一无所有地闯荡。一、初始WebSocket(1) 什么是websocket是一种在单个TCP连接上进行全双工通信的协议。使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。websocket是从HTML5开始⽀持的⼀种⽹⻚端和服务端保持"⻓连接"的消息推送机制。_websocket 线程https://blog.csdn.net/RNGWGzZs/article/details/131303941

(2)async def函数

在Python中,如果一个函数被定义为协程(使用async def定义),那么在调用它时必须使用await关键字。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值