目录
Websocket协议是对http的改进,可以实现client 与 server之间的双向通信; websocket连接一旦建立就始终保持,直到client或server 中断连接,弥补了http无法保持长连接的不足,方便了客户端应用与服务器之间实时通信。
实时更新数据场景,为什么不使用AJAX?
AJAX 采用http, 如果要实时更新页面,则需要不断地发送http 请求,无论是否有数据更新,产生大量冗余通信流量。而websocket是长连接双向通信,有数据更新时,服务器向客户机发送通知。
基于TCP,一次握手就能建立连接,支持双向通信,可保持长连接。

WebSocket 握手请求消息示例::
GET /chat HTTP/1.1
Host: normal-website.com
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: wDqumtseNBJdhkihL6PW7w==
Connection: keep-alive, Upgrade
Cookie: session=KOsEJNuflw4Rd9BDNrVmvwBF9rEijeE2
Upgrade: websocket
如果 Server 接收连接,返回响应
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: 0FFP+2nmNIf/h+4BP36k9uzrYGk=
响应码为101,表示切换为websocket 协议。
websocket 已得到主流浏览器,各编程语言的广泛支持,基本都提供了WebSocket高阶编程API,在一般场合下,可以替代socket低阶函数编程。python 提供了更简洁的编程实现方式。下面展示了实例代码方式,说明如何开发 Python websocket 服务器代码,python websocket 客户端, 以及javascript websocket 代码。
python 第3方库 websockets 提供了websocket 实现框架,支持asyncio, 性能强大,稳定性好,可以用于生产环境。
pip install websockets
Websocket服务端代码是面向多用户的长连接,因此本文采用了python3.7 版本的 asyncio 异步方式编写 websocket server 代码。
服务端也可使用 ThreadPoolExecutor 线程池方式同时处理多连接的场景,用户较多时,性能明显不如asyncio异步方式。
websockets 模块 server端的主要方法:
实现步骤:
websocket 地址格式:
下面是具体的代码 server.py
#!/usr/bin/python3
# 主要功能:创建1个基本的websocket server, 符合asyncio 开发要求
import asyncio
import websockets
from datetime import datetime
async def handler(websocket):
data = await websocket.recv()
reply = f"Data received as \"{data}\". time: {datetime.now()}"
print(reply)
await websocket.send(reply)
print("Send reply")
async def main():
async with websockets.serve(handler, "localhost", 9999):
await asyncio.Future() # run forever
if __name__ == "__main__":
asyncio.run(main())
服务端handler函数代码还有1种写法,适用性更好。
async def handler(websocket):
async for message in websocket:
reply = f"Data received as \"{message}\". time: {datetime.now()}"
print(reply)
await websocket.send(reply)
Websocket协议本身有心跳机制、连接检测机制,服务端无须关心客户端状态,一旦有异常,会自动断开连接。
Websockets提供了交互式测试命令,现在可以快速测试一下服务端是否能正常工作:
(1) 启动服务器: python server.py
(2) 通过命令行连接服务端,并向发送hello, world 消息,可以看到,收到了服务器的响应。
D:\workplace\python\projects\websock>python -m websockets ws://localhost:9999
Connected to ws://localhost:9999.
> hello, world
< Data received as "hello, world". time: 2023-04-01 09:24:14.787357
Connection closed: 1000 (OK).
当然实际应用时,应按下面步骤来编写客户端代码。
websockets 客户端提供的主要方法:
下面看一下示例 client.py
import asyncio
import websockets
import time
async def ws_client(url):
for i in range(1, 40):
async with websockets.connect(url) as websocket:
await websocket.send("Hello, I am PyPy.")
response = await websocket.recv()
print(response)
time.sleep(1)
asyncio.run(ws_client('ws://localhost:9999'))
目前主流的浏览器都支持websocket协议。
Javascript websocket 对象的主要属性与方法:
请参考菜鸟教程的这篇文章:https://www.runoob.com/html/html5-websocket.html
示例代码: client.html
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>websocket demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"> </script>
<script src="https://cdn.staticfile.org/popper.js/1.15.0/umd/popper.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>
<script type="text/javascript">
function WebSocketTest() {
text = document.getElementById("div_text");
if ("WebSocket" in window) {
// 打开一个 web socket
var ws = new WebSocket("ws://localhost:9999/handler");
ws.onopen = function () {
// Web Socket 已连接上,使用 send() 方法发送数据
ws.send("Javscript发送的数据");
text.innerHTML = "数据发送中...";
alert("数据发送中...");
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
text.innerHTML = "收到的数据:" + received_msg;
alert("数据已接收...");
};
ws.onclose = function () {
// 关闭 websocket
text.innerHTML = "连接已关闭...";
alert("连接已关闭...");
};
}
else {
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
}
</script>
</head>
<body>
<div class="col-md-6 m-5 p-2" id="div_ws">
<a class="btn btn-primary" href="javascript:WebSocketTest()">连接WebSocket</a>
</div>
<div class="col-md-6 border border-primary mx-5 p-2 " id="div_text" style="margin:20px;height:100px;">
display communicate text
</div>
</body>
</html>
上述3个文件都放在同1个目录下,打开两个终端窗口,先运行server.py, 再运行 client,py。
Output结果

在chrome 或edge 中运行client.html, 可以看到websocket 连接建立,发送,接收,关闭各阶段的状态。

能够看到,服务器与客户端之间的通信是双向的,而且是长连接,客户端断开后,服务器仍然保持侦听状态,而且不需要accept操作。websocket发送、接收文件也不需要 socket 对发送窗口 buffer 进行控制,因此是 socket 开发非常好的替代。
注:Python异步websocket服务器最终性能与代码质量、服务器硬件、网络等紧密相关,可以使用 Websocket-benchmarker 测试工具来测试服务器。
websockets 模块支持向所有连接的客户广播消息,
用1个简单的例子来演示,实现步骤:
将前面的server,.py 代码修改后如下:
#!/usr/bin/python3
# 主要功能:创建1个基本的websocket server, 符合asyncio 开发要求
import asyncio
import websockets
from datetime import datetime
CONNECTIONS = set()
async def send(websocket, message):
try:
await websocket.send(message)
except websockets.ConnectionClosed:
pass
async def broadcast(message=""):
# 向队列中的每个连接发送消息, 广播10次
for i in range(0,10):
message = f"Broadcast: New user joined, now time is {datetime.now()}"
if CONNECTIONS : # asyncio.wait doesn't accept an empty list
await asyncio.wait([
asyncio.create_task(send(websocket, message))
for websocket in CONNECTIONS
])
await asyncio.sleep(30) #每次广播间隔
async def handler(websocket):
CONNECTIONS.add(websocket) # 保存客户连接至集合
try:
# do other things
await websocket.wait_closed()
finally:
CONNECTIONS.remove(websocket)
async def main():
async with websockets.serve(handler, "localhost", 9998):
await asyncio.Future() # run forever
loop = asyncio.get_running_loop() #获取当前event_loop对象
loop.create_task(broadcast()) # 添加新的异步广播任务
if __name__ == "__main__":
asyncio.run(main())
注: 本例broadcast() 方法每30秒,就向全部用户发送广播。实际应用时可以保持永久循环
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------
网络编程套接字网络编程基础知识理解源`IP`地址和目的`IP`地址理解源MAC地址和目的MAC地址认识端口号理解端口号和进程ID理解源端口号和目的端口号认识`TCP`协议认识`UDP`协议网络字节序socket编程接口`sockaddr``UDP`网络程序服务器端代码逻辑:需要用到的接口服务器端代码`udp`客户端代码逻辑`udp`客户端代码`TCP`网络程序服务器代码逻辑多个版本服务器单进程版本多进程版本多线程版本线程池版本服务器端代码客户端代码逻辑客户端代码TCP协议通讯流程TCP协议的客户端/服务器程序流程三次握手(建立连接)数据传输四次挥手(断开连接)TCP和UDP对比网络编程基础知识
我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or
我创建了一个由于“在运行时执行的单例元类定义”而无法编码的对象(这段代码的描述是否正确?)。这是通过以下代码执行的:#defineclassXthatmyusesingletonclassmetaprogrammingfeatures#throughcallofmethod:break_marshalling!classXdefbreak_marshalling!meta_class=class我该怎么做才能使对象编码正确?是否可以从对象instance_of_x的classX中“移除”单例组件?我真的需要一个建议,因为我们的一些对象需要通过Marshal.dump序列化机制进行缓存。
我正在查看Ruby日志记录库Logging.logger方法并从sourceatgithub提出问题与这段代码有关:logger=::Logging::Logger.new(name)logger.add_appendersappenderlogger.additive=falseclass我知道类 最佳答案 这实际上删除了方法(当它实际被执行时)。这是确保close不会被调用两次的保障措施。看起来好像有嵌套的“class 关于Ruby元编程问题,我们在StackOverflow上找到一
使用Paperclip,我想从这样的URL抓取图像:require'open-uri'user.photo=open(url)问题是我最后得到一个像“open-uri20110915-4852-1o7k5uw”这样的文件名。有什么方法可以更改user.photo上的文件名?作为一个额外的变化,Paperclip将我的文件存储在S3上,所以如果我可以在初始分配中设置我想要的文件名就更好了,这样图像就会上传到正确的S3key。像这样:user.photo=open(url),:filename=>URI.parse(url).path 最佳答案
我正在开发一个xcode自动构建系统。在执行一些预构建验证时,我想检查指定的证书文件是否已被撤销。我了解securityverify-cert验证其他证书属性但不验证吊销。我如何检查撤销?我正在用Ruby编写构建系统,但我对任何语言的想法都持开放态度。我阅读了这个答案(Openssl-Howtocheckifacertificateisrevokedornot),但指向底部的链接(DoesOpenSSLautomaticallyhandleCRLs(CertificateRevocationLists)now?)进入的Material对我的目的来说有点过于复杂(用户上传已撤销的证书是一
关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby有很大不同。由于我与ruby之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?
我一直在寻找一种以编程方式或通过命令行将mp3转换为aac的方法,但没有成功。理想情况下,我有一段代码可以从我的Rails应用程序中调用,将mp3转换为aac。我安装了ffmpeg和libfaac,并能够使用以下命令创建aac文件:ffmpeg-itest.mp3-acodeclibfaac-ab163840dest.aac当我将输出文件的名称更改为dest.m4a时,它无法在iTunes中播放。谢谢! 最佳答案 FFmpeg提供AAC编码功能(如果您已编译它们)。如果您使用的是Windows,则可以从here获取完整的二进制文件。