官文
http://demo.pythoner.com/itt2zh/ch8.html
python 原生协程示例
import requests
import asyncio
@asyncio.coroutine
def download(url):
'''协程下载'''
resp = requests.get(url)
return resp.content, resp.status_code
@asyncio.coroutine # 如果用装饰器的话 调度协程需要用 yield from
def write_file(filename, content):
'''协程写数据'''
with open(filename, 'wb') as f:
f.write(content)
print(filename, 'Write Ok')
# @asyncio.coroutine 如果不用装饰器的话用 async关键字就行(async await)
async def save(url, filename):
'''协程保存文件'''
print('%s 正在下载中' % url)
await asyncio.sleep(1)
content, code = await download(url)
print(url, code)
await write_file(filename, content)
print('保存成功')
if __name__ == '__main__':
# 获取事件循环器对象
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait([
save('https://www.baidu.com', 'baidu.html'),
save('https://jd.com', 'jd.html'),
save('https://mail.qq.com', 'qq_mail.html')
]))
Tornado发起同步请求
from tornado.web import RequestHandler
from tornado.httpclient import HTTPClient, HTTPResponse, HTTPRequest # 框架提供发起网络请求方法(同步)
class DownloadHandler(RequestHandler):
def get(self):
url = self.get_query_argument('url')
client = HTTPClient()
response: HTTPResponse = client.fetch(url, validate_cert=False, method='POST') # 默认为True, 改为False为不验证证书(https)
print(response.body) # 响应体
print(response.code) # 响应状态码
print(response.headers) # 响应头
with open('index.html', 'wb') as f:
f.write(response.body) # 写入文件
self.write({'mes': '下载成功'})
注: HTTPClient 是HTTP请求的客户端类
client.fetch(request) 发送请求,request可以是str字符类的URL,也可以是HTTPRequest类对象
Tornado异步请求(长连接)
from tornado.httpclient import AsyncHTTPClient
class ....
@tornado.web.asynchronous # 把请求改完长连接,等待finish()结束才关闭连接
def get(self, *args, **kwargs):
'''发起异步请求'''
client = AsyncHTTPClient()
client.fetch('https://www.badiu.com', callback=self.save, validate_cert=False) # 是否验证ssl证书
def save(self, response: HTTPResponse): # 参数必须包含响应对象
'''异步后回调的函数'''
with open('index.html', 'wb') as f:
f.write(response.body)
print(response.effective_url, '下载成功')
self.write('下载完成')
self.finish()
Tornado异步请求(协程)
from tornado.httpclient import AsyncHTTPClient
import tornado.web
from tornado.web import gen
class ....
@tornado.web.asynchronous
@gen.coroutione # 可以将@gen.coroutione 改为async标识,将yield 改为await
def get(self, *args, **kwargs):
'''发起异步请求'''
client = AsyncHTTPClient()
resp = yield client.fetch('https://www.badiu.com', callback=self.save, validate_cert=False) # 是否验证ssl证书
self.save(response)
def save(self, response: HTTPResponse): # 参数必须包含响应对象
'''异步后回调的函数'''
with open('index.html', 'wb') as f:
f.write(response.body)
print(response.effective_url, '下载成功')
self.write('下载完成')
self.finish()
Socket(原生)
server
import socket # 导入 socket 模块
s = socket.socket() # 创建 socket 对象
s.bind(('127.0.0.1', 12345)) # 绑定端口
s.listen(5) # 等待客户端连接
while True:
c, addr = s.accept() # 建立客户端连接
print('连接地址:', addr)
c.send('欢迎访问!'.encode('utf-8'))
print(c.recv(1024).decode())
c.close() # 关闭
client
import socket # 导入 socket 模块
s = socket.socket() # 创建 socket 对象
s.connect_ex(('127.0.0.1', 12345))
print(s.recv(1024).decode('utf-8'))
s.send('ss'.encode())
s.close()
Tornado(websocket)
class EchoHandler(tornado.websocket.WebSocketHandler):
def open(self):
self.write_message('connected!')
def on_message(self, message):
self.write_message(message)
聊天室案例
server
# coding:utf-8
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
import os
import datetime
from tornado.web import RequestHandler
from tornado.options import define, options
from tornado.websocket import WebSocketHandler
define("port", default=8000, type=int)
class ChatHandler(WebSocketHandler):
users = set() # 用来存放在线用户的容器
def open(self):
self.users.add(self) # 建立连接后添加用户到容器中
for u in self.users: # 向已在线用户发送消息
u.write_message(
u"[%s]-[%s]-进入聊天室" % (self.request.remote_ip, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
def on_message(self, message):
print(message)
print(self.users)
for u in self.users: # 向在线用户广播消息
u.write_message(u"[%s]-[%s]-说:%s" % (
self.request.remote_ip, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), message))
def on_close(self):
self.users.remove(self) # 用户关闭连接后从容器中移除用户
for u in self.users:
u.write_message(
u"[%s]-[%s]-离开聊天室" % (self.request.remote_ip, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
def check_origin(self, origin):
return True # 允许WebSocket的跨域请求
if __name__ == '__main__':
tornado.options.parse_command_line()
app = tornado.web.Application([
(r"/ws", ChatHandler),
],
debug=True
)
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
print('Start ws:127.0.0.1:%s' % options.port)
tornado.ioloop.IOLoop.current().start()
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>聊天室</title>
</head>
<body>
<div id="contents" style="height:500px;overflow:auto;"></div>
<div>
<textarea id="msg"></textarea>
<a href="javascript:;" onclick="sendMsg()">发送</a>
</div>
<!-- jQuery -->
<script src="https://cdn.staticfile.org/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
var ws = new WebSocket("ws://127.0.0.1:8000/ws");
ws.onmessage = function(e) {
$("#contents").append("<p>" + e.data + "</p>");
}
function sendMsg() {
var msg = $("#msg").val();
ws.send(msg);
$("#msg").val("");
}
</script>
</body>
</html>