第7章 网络编程考察点
网络协议TCP/UDP/HTTP 常考题
浏览器输入一个url中间经历的过程
-
中间涉及到了哪些过程
-
包含哪些网络协议
-
每个协议都干了什么?
- DNS查询->TCP握手->HTTP请求->反向代理Nginx->uwsgi/gunicom->web app响应->TCP挥手
TCP三次握手过程
TCP三次握手, 状态转换。用wireshark抓包更直观
TCP四次挥手过程
TCP四次挥手,状态装换
client state C S server state
TCP/UDP的区别
TCP vs UDP
-
面向连接,可靠的,基于字节流
-
无连接,不可靠,面向报文
总结
-
记忆内容多,间隔记忆,多次重复,检索学习,穿插练习
-
费曼学习技巧,用简单的语言去教别人,检验自己是否真正的懂
-
如果解释过程中遇到障碍,重新学习知识点(分治)
HTTP协议常考题
HTTP请求的组成
HTTP协议由哪些部分组成?
-
状态行
-
请求头
-
消息主体
HTTP响应的组成
HTTP协议由哪些部分组成?
-
状态行
-
响应头
-
响应正文
HTTP常见状态码
-
1**信息,服务器收到请求,需要请求者继续执行操作
-
2**成功,操作被成功接受并处理
-
3**重定向,需要进一步操作完成请求
-
4**客户端错误,请求有语法错误或者无法完成请求
-
5**服务端错误,服务器在处理请求的过程中发生错误
-
牢记常见状态码的含义(220, 301, 302, 400, 403, 500等)
HTTP GET/POST的区别?
常见的HTTP方法: GET/POST/PUT/DELETE
GET 获取 POST 创建 PUT 更新 DELETE 删除
Restful 语义上一个是获取,一个是创建
GET是幂等的,POST非幂等
GET请求参数放到url(明文),长度限制,POST放到请求体,更安全
什么是幂等性
哪些HTTP 方法是幂等的
幂等方法是无论调用多少次都得到相同结果的HTTP方法
eg: a=4是幂等的,但是 a += 4 是非幂等
幂等的方法客户端可以安全地重发请求
什么是HTTP长连接
是TCP的应用层
HTTP persistent connection, HTTP 1.1
短连接: 建立连接...数据传输...关闭连接(连接的建立和关闭开销大)
长连接: Connection: Keep-alive 保持TCP连接不断开
如何区分不同HTTP请求?
Content-Length | Transfer-Encoding: chunked
- 客户端告诉服务端发送的HTTP请求有多长?
- Content-Length首部告诉浏览器报文中实体主体的大小
cookie和session的区别?
HTTP是无状态的,如何识别用户呢?
-
Session 一般是服务器生成之后给客户端(通过url参数或cookie)
-
Cookie 是实现session的一种机制,通过HTTP cookie字段实现
-
Session通过在服务器保存sessionid识别用户,cookie存储在客户端
总结:
-
请求和响应的组成
-
常用HTTP方法和幂等性
-
长连接,session和cookie
网络编程常考题
socket编程对于学习框架原理比较重要
TCP/UDP socket编程,HTTP编程
-
了解TCP编程的原理
-
了解UDP编程的原理
-
了解如何发送HTTP请求
TCP socket编程原理?
-
如何使用socket模块
-
如何建立TCP socket 客户端和服务端
-
客户端和服务端之间的通信
# !< server.py
import socket
import time
s = socket.socket()
s.bind('', 8888)
s.listen()
while True:
client, addr = s.accept() #return conn, addr
print(client)
timestr = time.ctime(time.time()) + '\r\n'
client.send(timestr.encode()) #send 参数 encode
client.close()
# !< client.py
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 8888))
s.sendall(b'Hello World')
data = s.recv(1024)
print(data.decode())
s.close()
使用socket发送HTTP请求
如何使用socket发送HTTP请求
-
使用socket接口发送HTTP请求
-
HTTP建立在TCP基础之上
-
HTTP是基于文本的协议
import socket
s = socket.socket()
s.connect(('www.baidu.com', 80))
http = b"GET /HTTP/1.1\r\nHost: www.baidu.com\r\n\r\n"
s.sendall(http)
buf = s.recv(1024)
print(buf)
s.close()
#接受完整的响应
IO多路复用常考题
五种IO模型
Unix网络编程提到的5种网络模型
-
Blocking IO
-
Nonblocking IO
-
IO multiplexing
-
Signal Driven IO
-
Asynchronous IO
两种不常用,一般使用IO多路复用比较多
如何提升服务器的并发能力呢?
-
多线程模型,创建新的线程处理请求
-
多进程模型,创建新的进程处理请求
-
线程/进程创建开销比较大,可以用线程池方式解决
-
线程和进程比较占用资源,难以同时创建太多
-
IO多路复用,实现单进程同时处理多个socket请求
什么是IO多路复用?
操作系统提供的同时监听多个socket的机制
为了实现高并发需要一种机制并发处理多个socket
linux常见的是select/poll/epoll
可以使用单线程单进程处理多个socket
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
py如何实现IO多路复用?
py封装操作系统的IO多路复用
-
py的IO多路复用基于操作系统实现(select/poll/epoll)
-
py2 select模块
-
py3 selectors模块
selectors模块
事件类型: EVENT_READ, EVENT_WRITE
DefaultSelector: 自动根据平台选取合适的IO模型
register(fileobj, events, data = None)
unregister(fileobj)
modify(fileobj, events, data=None)
select(timeout=None): returns[(key, events)]
close()
py 并发网络库常考题
Tornado/Gevent
用过哪些并发网络库?
Tornado vs Gevent vs Asyncio
Tornado 并发网络库和同时也是一个web微框架
Gevent 绿色线程(greenlet)实现并发, 猴子补丁修改内置socket
Asyncio Python3 内置的并发网络库,基于原生协程
Tornado框架
Tornado适用于微服务,实现Restful接口
底层基于linux多路复用
可以通过协程或者回调实现异步编程
相应的异步框架比如ORM不完善
import tornado.ioloop
import tornado.web
from tornado.httpclient import AsyncHTTPClient
class APIHandler(tornado.web.Requestandler):
async def get(self):
url = 'http://httpbin.org/get'
http_client = AsyncHTTPClient()
resp = http_client.fetch(url)
print(resp.body)
return resp.body
def make_app():
return tornado.web_Application([
(r"/api", APIHandler)
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
Gevent
高性能的并发网络库
基于轻量级绿色线程(greenlet)实现并发
需要注意monkey patch, gevent修改了内置的socket改为非阻塞
配合gunicorn 和 gevent 部署作为wsgi server
import gevent.monkey
gevent.monkey.patch_all() #修改内置的一些库非阻塞
import gevent
import requests
def fetch():
url = 'http://httpbin.org/get'
resp = request.get(url)
print(len(resp.text), i)
def asynchronous():
threads = []
for i in range(1, 10):
threads.append(gevent.spawn(fetch, i))
gevent.joinall(threads)
print('Asynchronous: ')
asynchronous()
Asyncio
基于协程实现的内置并发网络库
py3 引入到内置库,协程 + 事件循环
基于Aiohttp 可以实现一些小的服务
基于aiohttp并发请求
import asyncio
from aiohttp import Client Session #pip install aiohttp
async def fetch(url, session):
async with session.get(url) as response:
return await response.read()
async def run(r=10):
url = "http://httpbin.org/get"
tasks = []
async with ClientSession() as Session:
for i in range(r):
task = asyncio.ensure_future(fetch(url, session))
tasks.append(task)
responses = await asyncio.gather(*tasks)
for resp_body in responses:
print(len(resp_body))
loop = asyncio.get_event_loop()
future = asyncio.ensure_future(run())
loop.run_until_complete(future)
编写一个异步爬虫类
使用py的gevent或者asyncio编写一个异步爬虫类
该类可以传入需要抓取的网址列表
该类可以通过继承的方式提供一个处理response的方法