python---websocket的使用
一:简介
推文:WebSocket 是什么原理?为什么可以实现持久连接?
推文:WebSocket:5分钟从入门到精通(很好)
WebSocket协议是基于TCP的一种新的协议。WebSocket最初在HTML5规范中被引用为TCP连接,作为基于TCP的套接字API的占位符。它实现了浏览器与服务器全双工(full-duplex)通信。其本质是保持TCP连接,在浏览器和服务端通过Socket进行通信。
二:对比:
Http:
socket实现,单工通道(浏览器只发起,服务端只做响应),短连接,请求响应
WebSocket:
socket实现,双工通道,请求响应,推送。socket创建连接,不断开
三:socket实现步骤
服务端:
. 服务端开启socket,监听IP和端口
. 允许连接
* . 服务端接收到特殊值【加密sha1,特殊值,migic string="258EAFA5-E914-47DA-95CA-C5AB0DC85B11"】
* . 加密后的值发送给客户端
客户端:
. 客户端发起连接请求(IP和端口)
* . 客户端生成一个xxx,【加密sha1,特殊值,migic string="258EAFA5-E914-47DA-95CA-C5AB0DC85B11"】,向服务端发送一段特殊值
* . 客户端接收到加密的值
注意:这个魔数是固定的 258EAFA5-E914-47DA-95CA-C5AB0DC85B11
四:简单实现,实现连接
服务端:
# coding:utf8
# __author: Administrator
# date: //
# /usr/bin/env python
import socket,base64,hashlib def get_headers(data):
'''将请求头转换为字典'''
header_dict = {}
data = str(data,encoding="utf-8") header,body = data.split("\r\n\r\n",)
header_list = header.split("\r\n")
for i in range(,len(header_list)):
if i == :
if len(header_list[].split(" ")) == :
header_dict['method'],header_dict['url'],header_dict['protocol'] = header_list[].split(" ")
else:
k,v=header_list[i].split(":",)
header_dict[k]=v.strip()
return header_dict sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,)
sock.bind(("127.0.0.1",))
sock.listen() #等待用户连接
conn,addr = sock.accept()
print("conn from ",conn,addr)
#获取握手消息,magic string ,sha1加密
#发送给客户端
#握手消息
data = conn.recv()
headers = get_headers(data) # 对请求头中的sec-websocket-key进行加密
response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
"Upgrade:websocket\r\n" \
"Connection: Upgrade\r\n" \
"Sec-WebSocket-Accept: %s\r\n" \
"WebSocket-Location: ws://%s%s\r\n\r\n" magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' value = headers['Sec-WebSocket-Key'] + magic_string
ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest()) response_str = response_tpl % (ac.decode('utf-8'), headers['Host'], headers['url']) # 响应【握手】信息
conn.send(bytes(response_str, encoding='utf-8'))
'''
b'
GET / HTTP/1.1\r\n
Host: 127.0.0.1:\r\n
Connection: Upgrade\r\n
Pragma: no-cache\r\n
Cache-Control: no-cache\r\n
Upgrade: websocket\r\n
Origin: http://localhost:63342\r\n
Sec-WebSocket-Version: \r\n
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36\r\n
Accept-Encoding: gzip, deflate, br\r\n
Accept-Language: zh-CN,zh;q=0.8\r\n
Sec-WebSocket-Key: +uL/aiakjNABjEoMzAqm6Q==\r\n
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits\r\n\r\n'
'''
请求头
浏览器:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> </body>
</html>
<script>
ws =new WebSocket("ws://127.0.0.1:8080");
ws.onopen = function (ev) { //若是连接成功,onopen函数会执行
console.log()
}
</script>
五:数据接收规则
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length | #Payload len(第二个字节的前七位,最大127)决定头部的长度
|I|S|S|S| () |A| () | (/) | #若是小于126:Extended payload length扩展头部长度为0字节,后面全部为主体数据
|N|V|V|V| |S| | (if payload len==/) | #若是等于126:Extended payload length扩展头部长度为2字节,后面全部为主体数据
| |||| |K| | | #若是等于127:Extended payload length扩展头部长度为8字节,后面全部为主体数据
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == | #注意:主体数据中的前四位为mask掩码,用于后面的消息的解码,解码方式为循环异或操作
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to | #数据过长,需要分部发送,这时需要FIN和opcode
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
The MASK bit simply tells whether the message is encoded. Messages from the client must be masked, so your server should expect this to be . (In fact, section 5.1 of the spec says that your server must disconnect from a client if that client sends an unmasked message.) When sending a frame back to the client, do not mask it and do not set the mask bit. We'll explain masking later. Note: You have to mask messages even when using a secure socket.RSV1-3 can be ignored, they are for extensions. The opcode field defines how to interpret the payload data: 0x0 for continuation, 0x1 for text (which is always encoded in UTF-), 0x2 for binary, and other so-called "control codes" that will be discussed later. In this version of WebSockets, 0x3 to 0x7 and 0xB to 0xF have no meaning. The FIN bit tells whether this is the last message in a series. If it's 0, then the server will keep listening for more parts of the message; otherwise, the server should consider the message delivered. More on this later. Decoding Payload Length To read the payload data, you must know when to stop reading. That's why the payload length is important to know. Unfortunately, this is somewhat complicated. To read it, follow these steps: Read bits - (inclusive) and interpret that as an unsigned integer. If it's 125 or less, then that's the length; you're done. If it's , go to step . If it's 127, go to step 3.
Read the next bits and interpret those as an unsigned integer. You're done.
Read the next bits and interpret those as an unsigned integer (The most significant bit MUST be ). You're done.
Reading and Unmasking the Data If the MASK bit was set (and it should be, for client-to-server messages), read the next octets ( bits); this is the masking key. Once the payload length and masking key is decoded, you can go ahead and read that number of bytes from the socket. Let's call the data ENCODED, and the key MASK. To get DECODED, loop through the octets (bytes a.k.a. characters for text data) of ENCODED and XOR the octet with the (i modulo 4)th octet of MASK. In pseudo-code (that happens to be valid JavaScript): var DECODED = "";
for (var i = ; i < ENCODED.length; i++) {
DECODED[i] = ENCODED[i] ^ MASK[i % ];
} Now you can figure out what DECODED means depending on your application.
数据帧格式:
FIN:1个比特。
如果是1,表示这是消息(message)的最后一个分片(fragment),如果是0,表示不是是消息(message)的最后一个分片(fragment)。
RSV1, RSV2, RSV3:各占1个比特。
一般情况下全为0。当客户端、服务端协商采用WebSocket扩展时,这三个标志位可以非0,且值的含义由扩展进行定义。如果出现非零的值,且并没有采用WebSocket扩展,连接出错。
Opcode: 4个比特。
操作代码,Opcode的值决定了应该如何解析后续的数据载荷(data payload)。如果操作代码是不认识的,那么接收端应该断开连接(fail the connection)。可选的操作代码如下: %x0:表示一个延续帧。当Opcode为0时,表示本次数据传输采用了数据分片,当前收到的数据帧为其中一个数据分片。
%x1:表示这是一个文本帧(frame)
%x2:表示这是一个二进制帧(frame)
%x3-:保留的操作代码,用于后续定义的非控制帧。
%x8:表示连接断开。
%x9:表示这是一个ping操作。
%xA:表示这是一个pong操作。
%xB-F:保留的操作代码,用于后续定义的控制帧。
Mask: 1个比特。
表示是否要对数据载荷进行掩码操作。从客户端向服务端发送数据时,需要对数据进行掩码操作;从服务端向客户端发送数据时,不需要对数据进行掩码操作。 如果服务端接收到的数据没有进行过掩码操作,服务端需要断开连接。 如果Mask是1,那么在Masking-key中会定义一个掩码键(masking key),并用这个掩码键来对数据载荷进行反掩码。所有客户端发送到服务端的数据帧,Mask都是1。 掩码的算法、用途在下一小节讲解。
Payload length:数据载荷的长度,单位是字节。为7位,或7+16位,或1+64位。
假设数Payload length === x,如果 x为0~:数据的长度为x字节。
x为126:后续2个字节代表一个16位的无符号整数,该无符号整数的值为数据的长度。
x为127:后续8个字节代表一个64位的无符号整数(最高位为0),该无符号整数的值为数据的长度。
此外,如果payload length占用了多个字节的话,payload length的二进制表达采用网络序(big endian,重要的位在前)。
Masking-key:0或4字节(32位)
所有从客户端传送到服务端的数据帧,数据载荷都进行了掩码操作,Mask为1,且携带了4字节的Masking-key。如果Mask为0,则没有Masking-key。 备注:载荷数据的长度,不包括mask key的长度。
Payload data:(x+y) 字节
载荷数据:包括了扩展数据、应用数据。其中,扩展数据x字节,应用数据y字节。 扩展数据:如果没有协商使用扩展的话,扩展数据数据为0字节。所有的扩展都必须声明扩展数据的长度,或者可以如何计算出扩展数据的长度。此外,扩展如何使用必须在握手阶段就协商好。如果扩展数据存在,那么载荷数据长度必须将扩展数据的长度包含在内。 应用数据:任意的应用数据,在扩展数据之后(如果存在扩展数据),占据了数据帧剩余的位置。载荷数据长度 减去 扩展数据长度,就得到应用数据的长度。
实现规则解码:
def get_data(info): #info是我们连接后,接受的数据
payload_len = info[] &
if payload_len == :
extend_payload_len = info[:]
mask = info[:]
decoded = info[:]
elif payload_len == :
extend_payload_len = info[:]
mask = info[:]
decoded = info[:]
else:
extend_payload_len = None
mask = info[:]
decoded = info[:] bytes_list = bytearray() #这里我们使用字节将数据全部收集,再去字符串编码,这样不会导致中文乱码
for i in range(len(decoded)):
chunk = decoded[i] ^ mask[i % ]
bytes_list.append(chunk)
body = str(bytes_list, encoding='utf-8')
return body
实现循环获取数据
import socket,base64,hashlib def get_headers(data):
'''将请求头转换为字典'''
header_dict = {}
data = str(data,encoding="utf-8") header,body = data.split("\r\n\r\n",)
header_list = header.split("\r\n")
for i in range(,len(header_list)):
if i == :
if len(header_list[].split(" ")) == :
header_dict['method'],header_dict['url'],header_dict['protocol'] = header_list[].split(" ")
else:
k,v=header_list[i].split(":",)
header_dict[k]=v.strip()
return header_dict def get_data(info):
payload_len = info[] &
if payload_len == :
extend_payload_len = info[:]
mask = info[:]
decoded = info[:]
elif payload_len == :
extend_payload_len = info[:]
mask = info[:]
decoded = info[:]
else:
extend_payload_len = None
mask = info[:]
decoded = info[:] bytes_list = bytearray() #这里我们使用字节将数据全部收集,再去字符串编码,这样不会导致中文乱码
for i in range(len(decoded)):
chunk = decoded[i] ^ mask[i % ] #解码方式
bytes_list.append(chunk)
body = str(bytes_list, encoding='utf-8')
return body sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,)
sock.bind(("127.0.0.1",))
sock.listen() #等待用户连接
conn,addr = sock.accept()
print("conn from ",conn,addr)
#获取握手消息,magic string ,sha1加密
#发送给客户端
#握手消息
data = conn.recv() headers = get_headers(data) # 对请求头中的sec-websocket-key进行加密
response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
"Upgrade:websocket\r\n" \
"Connection: Upgrade\r\n" \
"Sec-WebSocket-Accept: %s\r\n" \
"WebSocket-Location: ws://%s%s\r\n\r\n" magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' value = headers['Sec-WebSocket-Key'] + magic_string
ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest()) response_str = response_tpl % (ac.decode('utf-8'), headers['Host'], headers['url']) # 响应【握手】信息
conn.send(bytes(response_str, encoding='utf-8')) #可以进行通信
while True:
data = conn.recv()
data = get_data(data)
print(data)
服务端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> </body>
</html>
<script>
ws =new WebSocket("ws://127.0.0.1:8080");
ws.onopen = function (ev) { //若是连接成功,onopen函数会执行
console.log();
ws.send("你好");
}
</script>
客户端代码

注意:使用控制台完成发送,而不是刷新页面,会报错,因为我们关闭了连接,试图将关闭信号字节编码出错。这里我们需要利用mask(第二字节中,1表示连接,0断开)
六:数据发送规则(需要发送二进制包struct模块)
def send_msg(conn, msg_bytes):
"""
WebSocket服务端向客户端发送消息
:param conn: 客户端连接到服务器端的socket对象,即: conn,address = socket.accept()
:param msg_bytes: 向客户端发送的字节
:return:
"""
import struct token = b"\x81" #接收的第一字节,一般都是x81不变
length = len(msg_bytes)
if length < :
token += struct.pack("B", length)
elif length <= 0xFFFF:
token += struct.pack("!BH", , length)
else:
token += struct.pack("!BQ", , length) msg = token + msg_bytes
conn.send(msg)
return True

实现发送数据
# coding:utf8
# __author: Administrator
# date: //
# /usr/bin/env python
import socket,base64,hashlib def get_headers(data):
'''将请求头转换为字典'''
header_dict = {}
data = str(data,encoding="utf-8") header,body = data.split("\r\n\r\n",)
header_list = header.split("\r\n")
for i in range(,len(header_list)):
if i == :
if len(header_list[].split(" ")) == :
header_dict['method'],header_dict['url'],header_dict['protocol'] = header_list[].split(" ")
else:
k,v=header_list[i].split(":",)
header_dict[k]=v.strip()
return header_dict def get_data(info):
payload_len = info[] &
if payload_len == :
extend_payload_len = info[:]
mask = info[:]
decoded = info[:]
elif payload_len == :
extend_payload_len = info[:]
mask = info[:]
decoded = info[:]
else:
extend_payload_len = None
mask = info[:]
decoded = info[:] bytes_list = bytearray() #这里我们使用字节将数据全部收集,再去字符串编码,这样不会导致中文乱码
for i in range(len(decoded)):
chunk = decoded[i] ^ mask[i % ] #解码方式
bytes_list.append(chunk)
body = str(bytes_list, encoding='utf-8')
return body def send_msg(conn, msg_bytes):
"""
WebSocket服务端向客户端发送消息
:param conn: 客户端连接到服务器端的socket对象,即: conn,address = socket.accept()
:param msg_bytes: 向客户端发送的字节
:return:
"""
import struct token = b"\x81" #接收的第一字节,一般都是x81不变
length = len(msg_bytes)
if length < :
token += struct.pack("B", length)
elif length <= 0xFFFF:
token += struct.pack("!BH", , length)
else:
token += struct.pack("!BQ", , length) msg = token + msg_bytes
conn.send(msg)
return True sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,)
sock.bind(("127.0.0.1",))
sock.listen() #等待用户连接
conn,addr = sock.accept()
#获取握手消息,magic string ,sha1加密
#发送给客户端
#握手消息
data = conn.recv() headers = get_headers(data) # 对请求头中的sec-websocket-key进行加密
response_tpl = "HTTP/1.1 101 Switching Protocols\r\n" \
"Upgrade:websocket\r\n" \
"Connection: Upgrade\r\n" \
"Sec-WebSocket-Accept: %s\r\n" \
"WebSocket-Location: ws://%s%s\r\n\r\n" magic_string = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11' value = headers['Sec-WebSocket-Key'] + magic_string
ac = base64.b64encode(hashlib.sha1(value.encode('utf-8')).digest()) response_str = response_tpl % (ac.decode('utf-8'), headers['Host'], headers['url']) # 响应【握手】信息
conn.send(bytes(response_str, encoding='utf-8')) #可以进行通信
while True:
data = conn.recv()
data = get_data(data)
print(data)
send_msg(conn,bytes(data+"geah",encoding="utf-8"))
服务端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> </body>
</html>
<script>
ws =new WebSocket("ws://127.0.0.1:8080");
ws.onopen = function (ev) { //若是连接成功,onopen函数会执行
console.log();
ws.send("你好");
}
ws.onmessage = function (ev) {
console.log(ev);
}
</script>
前端onmessage 当数据接收会触发

七:tornado实现websocket聊天室
tornado服务端
import tornado.ioloop
import tornado.web
import tornado.websocket
import datetime class MainHandler(tornado.web.RequestHandler):
def get(self): self.render("s1.html") def post(self, *args, **kwargs):
pass users = set()
class ChatHandler(tornado.websocket.WebSocketHandler):
def open(self, *args, **kwargs):
'''客户端连接'''
print("connect....")
print(self.request)
users.add(self) def on_message(self, message):
'''有消息到达'''
now = datetime.datetime.now()
content = self.render_string("recv_msg.html",date=now.strftime("%Y-%m-%d %H:%M:%S"),msg=message)
for client in users:
if client == self:
continue
client.write_message(content) def on_close(self):
'''客户端主动关闭连接'''
users.remove(self) st ={
"template_path": "template",#模板路径配置
"static_path":'static',
} #路由映射 匹配执行,否则404
application = tornado.web.Application([
("/index",MainHandler),
("/wschat",ChatHandler),
],**st) if __name__=="__main__":
application.listen() #io多路复用
tornado.ioloop.IOLoop.instance().start()
前端模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/static/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/css/nifty.min.css" rel="stylesheet">
<link href="/static/css/demo/nifty-demo-icons.min.css" rel="stylesheet">
<link href="/static/css/demo/nifty-demo.min.css" rel="stylesheet">
<link href="/static/plugins/pace/pace.min.css" rel="stylesheet">
<script src="/static/js/jquery-2.2.4.min.js"></script>
<script src="/static/plugins/pace/pace.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<script src="/static/js/nifty.min.js"></script>
<script src="/static/js/demo/nifty-demo.min.js"></script>
<script src="/static/plugins/flot-charts/jquery.flot.min.js"></script>
<script src="/static/plugins/flot-charts/jquery.flot.resize.min.js"></script>
<script src="/static/plugins/gauge-js/gauge.min.js"></script>
<script src="/static/plugins/skycons/skycons.min.js"></script>
<script src="/static/plugins/easy-pie-chart/jquery.easypiechart.min.js"></script>
<script src="/static/js/demo/widgets.js"></script>
</head>
<body>
<div id="container" class="effect aside-bright mainnav-sm aside-right aside-in">
<div class="boxed">
<div id="content-container">
<div class="row">
<div class="col-md-8 col-lg-8 col-sm-8"> <!--Chat widget-->
<!--===================================================-->
<div class="panel" style="height: 640px">
<!--Heading-->
<div class="panel-heading">
<h3 class="panel-title">Chat</h3>
</div> <!--Widget body-->
<div style="height:510px;padding-top:0px;" class="widget-body">
<div class="nano">
<div class="nano-content pad-all">
<ul class="list-unstyled media-block"> </ul>
</div>
</div> <!--Widget footer-->
<div class="panel-footer" style="height: 90px;">
<div class="row">
<div class="col-xs-9">
<input type="text" placeholder="Enter your text" class="form-control chat-input">
</div>
<div class="col-xs-3">
<button class="btn btn-primary btn-block" onclick="sendMsg(this);" type="submit">Send</button>
</div>
</div>
</div>
</div>
</div>
<!--===================================================-->
<!--Chat widget--> </div>
<div class="col-md-4 col-lg-4 col-sm-4">
<aside id="aside-container">
<div id="aside">
<div class="nano has-scrollbar">
<div class="nano-content" tabindex="" style="right: -17px;"> <!--Nav tabs-->
<!--================================-->
<ul class="nav nav-tabs nav-justified">
<li class="active">
<a href="#demo-asd-tab-1" data-toggle="tab">
<i class="demo-pli-speech-bubble-7"></i>
</a>
</li>
</ul>
<!--================================-->
<!--End nav tabs--> <!-- Tabs Content -->
<!--================================-->
<div class="tab-content">
<div class="tab-pane fade in active" id="demo-asd-tab-1">
<p class="pad-hor text-semibold text-main">
<span class="pull-right badge badge-success"></span> Friends
</p> </div>
</div>
</div>
<div class="nano-pane" style="display: none;"><div class="nano-slider" style="height: 4059px; transform: translate(0px, 0px);"></div></div></div>
</div>
</aside>
</div>
</div>
</div>
</div>
</div>
</body>
</html> <script>
ws = new WebSocket("ws://127.0.0.1:8080/wschat"); function sendMsg(ths) {
var dt = new Date()
var now_time = dt.toLocaleString(); var msg = $(ths).parents(".row").find(".chat-input").val();
$(ths).parents(".row").find(".chat-input").empty();
var li = '<li class="mar-btm"><div class="media-right"><img src="" class="img-circle img-sm" alt="Profile Picture"></div>';
li += '<div class="media-body pad-hor speech-right"><div class="speech"><a href="#" class="media-heading">游客</a>';
li += '<p>'+msg+'</p>';
li += '<p class="speech-time">';
li += '<i class="demo-pli-clock icon-fw"></i>'+now_time;
li += '</p></div></div></li>';
$(ths).parents(".widget-body").find(".list-unstyled").append(li);
$(ths).parents(".panel-footer").find(".chat-input").val("");
ws.send(msg);
} ws.onmessage=function (ev) {
$(".list-unstyled").append(ev.data);
}
</script>
s1.html
消息插件
<li class="mar-btm">
<div class="media-left">
<img src="img/profile-photos/1.png" class="img-circle img-sm" alt="Profile Picture">
</div>
<div class="media-body pad-hor">
<div class="speech">
<a href="#" class="media-heading">游客</a>
<p>{{msg}}</p>
<p class="speech-time">
<i class="demo-pli-clock icon-fw"></i>{{date}}
</p>
</div>
</div>
</li>
recv_msg.html
实现效果
游客一:

游客二

python---websocket的使用的更多相关文章
- Python WebSocket长连接心跳与短连接
python websocket 安装 pip install websocket-client 先来看一下,长连接调用方式: ws = websocket.WebSocketApp("ws ...
- python websocket学习使用
前言 今天看了一些资料,记录一下心得. websocket是html5引入的一个新特性,传统的web应用是通过http协议来提供支持,如果要实时同步传输数据,需要轮询,效率低下 websocket是类 ...
- python websocket网页实时显示远程服务器日志信息
功能:用websocket技术,在运维工具的浏览器上实时显示远程服务器上的日志信息 一般我们在运维工具部署环境的时候,需要实时展现部署过程中的信息,或者在浏览器中实时显示程序日志给开发人员看.你还在用 ...
- Python websocket
一.自己实现websocket 网上流传的都是Python2的websocket实现 # coding=utf8 # !/usr/bin/python import struct, socket im ...
- 运维开发:python websocket网页实时显示远程服务器日志信息
功能:用websocket技术,在运维工具的浏览器上实时显示远程服务器上的日志信息 一般我们在运维工具部署环境的时候,需要实时展现部署过程中的信息,或者在浏览器中实时显示程序日志给开发人员看.你还在用 ...
- python websocket Django 实时消息推送
概述: WebSocket 是什么? WebSocket 是 HTML5 提供的一种浏览器与服务器间进行全双工通讯的协议.依靠这种协议可以实现客户端和服务器端 ,一次握手,双向实时通信. WebSoc ...
- python websocket 再线聊天室的 Demo
服务端 import tornado.web import tornado.ioloop import tornado.httpserver import tornado.options import ...
- python websocket 客户端连接
# -*- coding: utf-8 -*-import jsonimport websocketimport _thread as thread # try:# import thread# ex ...
- python websocket client 使用
import websocket ws = websocket.WebSocket() ws.connect("xx.xx.xx") ws.send("string&qu ...
- Python基于websocket实时通信的实现—GoEasy
Python websocket实时消息推送 在这里我记录一下之前如何实现服务器端与客户端实时通信: 实现步骤如下: 1. 获取GoEasy appkey. 在goeasy官网上注册一个 ...
随机推荐
- 撤销 git merge
由于太多人问怎么撤销 merge 了,于是 git 官方出了这份教程,表示在 git 现有的思想体系下怎么达到撤销 merge 的目标. 方法一,reset 到 merge 前的版本,然后再重做接下来 ...
- Thunder团队第七周 - Scrum会议4
Scrum会议4 小组名称:Thunder 项目名称:i阅app Scrum Master:翟宇豪 工作照片: 宋雨在照相,所以不在相片中. 参会成员: 王航:http://www.cnblogs.c ...
- 个人作业四:注册github
注册Github账户 账户名称:liurunhan Github地址:https://github.com/liurunhan
- OOP 学习笔记汇总
1.1 引用 1.2 const关键字 1.3 动态内存分配 1.4 内联函数和重载函数函数参数缺省值 1.5 类和对象的基本概念与用法1 2.1 类和对象的基本概念2
- 《我是一只it小小鸟》观后感
在这个学期开始的时候我们的老师推荐给我们这本书.在很多的网站上只要一提到IT,总会有人推荐这本书,我在读这本书之前看了很多关于它的书评,其中有一位网友的一句话让我对它产生了很大的兴趣:“印象最深的是书 ...
- 使用windows live writer发表的博客
试插入代码 #include <iostream.h> using namespace std; int main() { cout<<"hello world&qu ...
- Mac下Java JNI 调C
简介 JNI的实现步骤如下: 编写带有native声明的方法的Java类 使用javac命令编译编写的Java类 使用java -jni className 来生成后缀名为.h的头文件 使用其他语言( ...
- 【C++】new和delete表达式与内存管理
new和delete表达式可以用来动态创建和释放单个对象,也可以用来动态创建和释放动态数组. 定义变量时,必须指定其数据类型和名字.而动态创建对象时,只需指定其数据类型,而不必为该对象命名.new表达 ...
- python的N个小功能(更新文件)
########################################################################## #对于第二份文件:第一份与第二份不相同,以第二份为 ...
- 对Spark2.2.0文档的学习1-Cluster Mode Overview
Cluster Mode Overview Link:http://spark.apache.org/docs/2.2.0/cluster-overview.html Spark应用(Applicat ...