非阻塞网络IO
- 非阻塞的特点:当没有数据来的时候不阻塞当前进程等待,而是报出一个异常 (套接字.setblocking(False))
IO多路复用
- 多路IO好处就在于单个process就可以同时处理多个网络连接的IO
- 特点: 通过一种机制使一个进程能同时等待多个文件描述符,而这些文件描述(套接字描述符)其中的任意一个进入读就绪状态,epoll()函数就可以返回
- epoll 只能在Linux中使用
- EPOLLIN(可读)
- EPOLLOUT(可写)
- EPOLLET(ET模式)
水平触发和边缘触发
- LT(level trigger):会在数据存在的情况下一直通知
- ET(edge trigger): 只在数据到达的一刻通知一次
文件描述符
- 文件描述符就是对进程内部所拥有文件资源的一种描述的符号,是一个无符号整数(0,1,2…)
- 启动一个程序默认启动 标准输入、标准输出、标准错误 sock.fileno()
web服务器-多线程
import socket
import threading
def request_handler(client_socket):
"""专门来处理客户端请求的函数"""
recv_data = client_socket.recv(1024)
if not recv_data:
print("客户端已断开连接")
client_socket.close()
return
recv_str_data = recv_data.decode()
request_line = recv_str_data.split("\r\n")[0]
path_info = request_line.split(" ")[1]
if path_info == "/":
path_info = "/index.html"
try:
with open("./static" + path_info, "rb") as f:
ret = f.read()
except Exception as e:
response_line = "HTTP/1.1 404 NOt Found\r\n"
response_header = "Server: PythonServer2.0\r\n"
response_body = "ERROR"
response_data = response_line + response_header + "\r\n" + response_body
client_socket.send(response_data.encode())
else:
response_line = "HTTP/1.1 200 OK\r\n"
response_header = "Server: PythonServer1.0\r\n"
request_body = ret
data = (response_line + response_header + "\r\n").encode() + request_body
client_socket.send(data)
finally:
client_socket.close()
if __name__ == '__main__':
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 8888))
server_socket.listen(128)
while True:
client_socket, client_address = server_socket.accept()
print("接收到来自客户端%s的请求" % str(client_address))
thd = threading.Thread(target=request_handler, args=(client_socket, ))
thd.start()
web服务器-多进程
import socket
import multiprocessing
def request_handler(client_socket):
"""专门来处理客户端请求的函数"""
recv_data = client_socket.recv(1024)
if not recv_data:
print("客户端已断开连接")
client_socket.close()
return
recv_str_data = recv_data.decode()
request_line = recv_str_data.split("\r\n")[0]
path_info = request_line.split(" ")[1]
if path_info == "/":
path_info = "/index.html"
try:
with open("./static" + path_info, "rb") as f:
ret = f.read()
except Exception as e:
response_line = "HTTP/1.1 404 NOt Found\r\n"
response_header = "Server: PythonServer2.0\r\n"
response_body = "ERROR"
response_data = response_line + response_header + "\r\n" + response_body
client_socket.send(response_data.encode())
else:
response_line = "HTTP/1.1 200 OK\r\n"
response_header = "Server: PythonServer1.0\r\n"
request_body = ret
data = (response_line + response_header + "\r\n").encode() + request_body
client_socket.send(data)
finally:
client_socket.close()
if __name__ == '__main__':
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 8888))
server_socket.listen(128)
while True:
client_socket, client_address = server_socket.accept()
print("接收到来自客户端%s的请求" % str(client_address))
pro = multiprocessing.Process(target=request_handler, args=(client_socket,))
pro.start()
client_socket.close()
web服务器-面向对象
import socket
import multiprocessing
class HTTPServer(object):
def __init__(self):
"""创建服务器相关资源"""
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 8888))
server_socket.listen(128)
self.server_socket = server_socket
def request_handler(self, client_socket):
"""专门来处理客户端请求的函数"""
recv_data = client_socket.recv(1024)
if not recv_data:
print("客户端已断开连接")
client_socket.close()
return
recv_str_data = recv_data.decode()
request_line = recv_str_data.split("\r\n")[0]
path_info = request_line.split(" ")[1]
if path_info == "/":
path_info = "/index.html"
try:
with open("./static" + path_info, "rb") as f:
ret = f.read()
except Exception as e:
response_line = "HTTP/1.1 404 NOt Found\r\n"
response_header = "Server: PythonServer2.0\r\n"
response_body = "ERROR"
response_data = response_line + response_header + "\r\n" + response_body
client_socket.send(response_data.encode())
else:
response_line = "HTTP/1.1 200 OK\r\n"
response_header = "Server: PythonServer1.0\r\n"
request_body = ret
data = (response_line + response_header + "\r\n").encode() + request_body
client_socket.send(data)
finally:
client_socket.close()
def start(self):
while True:
client_socket, client_address = self.server_socket.accept()
print("接收到来自客户端%s的请求" % str(client_address))
pro = multiprocessing.Process(target=self.request_handler, args=(client_socket,))
pro.start()
client_socket.close()
if __name__ == '__main__':
hs = HTTPServer()
hs.start()
web服务器-协程
from gevent import monkey
monkey.patch_all()
import gevent
import socket
class HTTPServer(object):
def __init__(self):
"""创建服务器相关资源"""
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(("", 8888))
server_socket.listen(128)
self.server_socket = server_socket
def request_handler(self, client_socket):
"""专门来处理客户端请求的函数"""
recv_data = client_socket.recv(1024)
if not recv_data:
print("客户端已断开连接")
client_socket.close()
return
recv_str_data = recv_data.decode()
request_line = recv_str_data.split("\r\n")[0]
path_info = request_line.split(" ")[1]
if path_info == "/":
path_info = "/index.html"
try:
with open("./static" + path_info, "rb") as f:
ret = f.read()
except Exception as e:
response_line = "HTTP/1.1 404 NOt Found\r\n"
response_header = "Server: PythonServer2.0\r\n"
response_body = "ERROR"
response_data = response_line + response_header + "\r\n" + response_body
client_socket.send(response_data.encode())
else:
response_line = "HTTP/1.1 200 OK\r\n"
response_header = "Server: PythonServer1.0\r\n"
request_body = ret
data = (response_line + response_header + "\r\n").encode() + request_body
client_socket.send(data)
finally:
client_socket.close()
def start(self):
while True:
client_socket, client_address = self.server_socket.accept()
print("接收到来自客户端%s的请求" % str(client_address))
gevent.spawn(self.request_handler, client_socket)
if __name__ == '__main__':
hs = HTTPServer()
hs.start()
web服务器-命令行参数控制端口
from gevent import monkey
monkey.patch_all()
import socket
import gevent
import sys
class HTTPServer(object):
def __init__(self,port):
"""创建服务器相关的资源 """
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind(('', port))
server_socket.listen(128)
self.server_socket = server_socket
def request_handler(self, client_socket):
"""专门用来处理客户端请求的函数"""
recv_data = client_socket.recv(4096)
if not recv_data:
print("客户端已经断开连接")
client_socket.close()
return
recv_str_data = recv_data.decode()
data_list = recv_str_data.split('\r\n')
request_line = data_list[0]
path_info = request_line.split(" ")[1]
print(path_info)
if path_info == '/':
path_info = '/index.html'
try:
with open("./static" + path_info, "rb") as file:
file_data = file.read()
except Exception as e:
response_line = "HTTP/1.1 404 Not Found\r\n"
response_header = "Server: PythonServer2.0\r\n"
response_body = "ERROR"
response_data = response_line + response_header + "\r\n" + response_body
client_socket.send(response_data.encode())
else:
response_line = "HTTP/1.1 200 OK\r\n"
response_header = "Server: PythonServer2.0\r\n"
response_body = file_data
response_data = (response_line + response_header + "\r\n").encode() + response_body
client_socket.sendall(response_data)
finally:
client_socket.close()
def start(self):
while True:
client_socket, client_addr = self.server_socket.accept()
print("接受到来自%s的连接请求" % str(client_addr))
gevent.spawn(self.request_handler, client_socket)
def main():
if len(sys.argv) != 2:
print("参数错误")
return
port = sys.argv[1]
if not port.isdigit():
print("端口号应该是数字")
return
port_number = int(port)
httpserver = HTTPServer(port_number)
httpserver.start()
if __name__ == '__main__':
main()