一、HTTP 和WebSocket
先来看一下HTTP 和WebSocket的关系,以及为什么使用websockets不使用HTTP
(1)关系:
-
HTTP (Hypertext Transfer Protocol): HTTP 是万维网的数据通信的核心。它是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP 是无状态的,意味着每个请求都是独立的,服务器不会在两个请求之间保留任何数据(状态)。
-
RESTful: RESTful 是一种基于 HTTP 的架构风格,它定义了一组约束条件和原则,用于创建 Web 服务。这些约束条件和原则包括使用 HTTP 方法(如 GET、POST、PUT、DELETE),使用 URI 来标识资源,以及使用 HTTP 状态码来表示请求的结果。
-
WebSocket: WebSocket 是一种在单个 TCP 连接上提供全双工通信信道的协议。它提供了一种在客户端和服务器之间进行双向通信的机制。WebSocket 协议在 HTTP 协议的基础上进行了扩展,以实现全双工通信。
这三种协议的关系可以这样理解:HTTP 是基础,RESTful 是基于 HTTP 的一种设计风格,而 WebSocket 是 HTTP 协议的扩展,用于实现实时双向通信。
(2)为什么使用websockets不使用HTTP:
- 使用http
原生的http能实现吗? 当然!客户端显然可以采用一种 "轮询"的⽅式,不停向服务器发送http报头,得到结果反馈。但这其实是一种 "伪服务器推"的方式,并且 轮询的成本⽐较⾼,服务端也不能及时的获取到消息的响应。
- 使用WebSocket
使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输,适用于服务器和客户端需要大量数据交互的场景。
大家可以看一下此链接,将HTTP 和WebSocket的关系讲的很通俗易懂,参考链接:我们来谈谈websocket_websocket 线程_RNGWGzZs的博客-优快云博客
二、代码示例
服务端:接收客户端的消息--->更改空调状态(全局变量ac_status['on'])--->发送通知给所有客户端(空调状态改变)
客户端:发送消息给服务端,更改服务端空调的状态 + 实时接收服务端发送的通知(空调状态)
注:打开这个auto_change_ac_status函数,服务端每3秒可自动更改一次空调状态
服务端(Python):
import asyncio
import json
import websockets
ac_status = {
'on': True,
'temperature': 22
}
clients = set()
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:
received_message=await websocket.recv()
print(f"Received message: {received_message}")
# 根据接收到的消息更改空调的状态
if received_message == "turn on":
ac_status['on'] = True
await notify_clients()
elif received_message == "turn off":
ac_status['on'] = False
await notify_clients()
elif received_message.startswith("set temperature"):
temperature = int(received_message.split()[-1])
ac_status['temperature'] = temperature
await notify_clients()
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()
start_server = websockets.serve(server, "0.0.0.0", 5000)
if __name__ == '__main__':
asyncio.get_event_loop().run_until_complete(start_server)
# asyncio.ensure_future(auto_change_ac_status())
asyncio.get_event_loop().run_forever()
客户端(C++):
#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;
websocket_callback_client client;
void send_message(string message) {
websocket_outgoing_message msg;
msg.set_utf8_message(message);
client.send(msg).wait();
}
int main()
{
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;
});
send_message("turn off");
//阻塞主线程 防止退出
std::string line;
std::getline(std::cin, line);
return 0;
}