web静态服务器
非阻塞網(wǎng)絡(luò)IO
- 非阻塞的特點(diǎn):當(dāng)沒有數(shù)據(jù)來的時(shí)候不阻塞當(dāng)前進(jìn)程等待,而是報(bào)出一個(gè)異常 (套接字.setblocking(False))
IO多路復(fù)用
- 多路IO好處就在于單個(gè)process就可以同時(shí)處理多個(gè)網(wǎng)絡(luò)連接的IO
- 特點(diǎn): 通過一種機(jī)制使一個(gè)進(jìn)程能同時(shí)等待多個(gè)文件描述符,而這些文件描述(套接字描述符)其中的任意一個(gè)進(jìn)入讀就緒狀態(tài),epoll()函數(shù)就可以返回
- epoll 只能在Linux中使用
- EPOLLIN(可讀)
- EPOLLOUT(可寫)
- EPOLLET(ET模式)
水平觸發(fā)和邊緣觸發(fā)
- LT(level trigger):會(huì)在數(shù)據(jù)存在的情況下一直通知
- ET(edge trigger): 只在數(shù)據(jù)到達(dá)的一刻通知一次
文件描述符
- 文件描述符就是對(duì)進(jìn)程內(nèi)部所擁有文件資源的一種描述的符號(hào),是一個(gè)無符號(hào)整數(shù)(0,1,2...)
- 啟動(dòng)一個(gè)程序默認(rèn)啟動(dòng) 標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤 sock.fileno()
web服務(wù)器-多線程
import socket import threadingdef request_handler(client_socket):"""專門來處理客戶端請(qǐng)求的函數(shù)"""# 接收用戶請(qǐng)求recv_data = client_socket.recv(1024)if not recv_data:print("客戶端已斷開連接")client_socket.close()return# 解碼數(shù)據(jù)recv_str_data = recv_data.decode()# 切割請(qǐng)求數(shù)據(jù)-->列表,取第0個(gè)元素 GET /index2.html HTTP/1.1\r\nrequest_line = recv_str_data.split("\r\n")[0]# 再次切割 取列表第一個(gè)元素 就是用戶路徑 /index2.htmlpath_info = request_line.split(" ")[1]if path_info == "/":path_info = "/index.html"try:# # 嘗試打開用戶需要的文件, 不存在則拋出異常# f = open("./static" + path_info, "rb")# # 如果文件較大 容易產(chǎn)生隱患# # 讀出文件數(shù)據(jù)# ret = f.read()# f.close()# with 語句 自動(dòng)將對(duì)象的資源驚醒釋放--> 上下文管理# 支持的數(shù)據(jù)資源有文件 socket 互斥鎖等# static文件夾為你訪問的數(shù)據(jù)(自備),與本程序放在同一目錄下with open("./static" + path_info, "rb") as f:# 讀出文件數(shù)據(jù)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_bodyclient_socket.send(response_data.encode())else:# 響應(yīng)行 響應(yīng)頭 \r\n 響應(yīng)體# 響應(yīng)行response_line = "HTTP/1.1 200 OK\r\n"# 響應(yīng)頭response_header = "Server: PythonServer1.0\r\n"# 響應(yīng)體request_body = ret# 報(bào)文拼接data = (response_line + response_header + "\r\n").encode() + request_body# 發(fā)送client_socket.send(data)finally:# 關(guān)閉client_socket.close()if __name__ == '__main__':# 創(chuàng)建套接字server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 地址重用(1.設(shè)置 0.取消)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 綁定端口server_socket.bind(("", 8888))# 監(jiān)聽server_socket.listen(128)while True:# 取出一個(gè)客戶端套接字用以通信client_socket, client_address = server_socket.accept()print("接收到來自客戶端%s的請(qǐng)求" % str(client_address))# request_handler(client_socket)# 為每個(gè)客戶端請(qǐng)求的執(zhí)行都創(chuàng)建一個(gè)線程# 創(chuàng)建線程thd = threading.Thread(target=request_handler, args=(client_socket, ))thd.start() 復(fù)制代碼web服務(wù)器-多進(jìn)程
import socket import multiprocessingdef request_handler(client_socket):"""專門來處理客戶端請(qǐng)求的函數(shù)"""# 接收用戶請(qǐng)求recv_data = client_socket.recv(1024)if not recv_data:print("客戶端已斷開連接")client_socket.close()return# 解碼數(shù)據(jù)recv_str_data = recv_data.decode()# 切割請(qǐng)求數(shù)據(jù)-->列表,取第0個(gè)元素 GET /index2.html HTTP/1.1\r\nrequest_line = recv_str_data.split("\r\n")[0]# 再次切割 取列表第一個(gè)元素 就是用戶路徑 /index2.htmlpath_info = request_line.split(" ")[1]if path_info == "/":path_info = "/index.html"try:# # 嘗試打開用戶需要的文件, 不存在則拋出異常# f = open("./static" + path_info, "rb")# # 如果文件較大 容易產(chǎn)生隱患# # 讀出文件數(shù)據(jù)# ret = f.read()# f.close()# with 語句 自動(dòng)將對(duì)象的資源驚醒釋放--> 上下文管理# 支持的數(shù)據(jù)資源有文件 socket 互斥鎖等 # static文件夾為你訪問的數(shù)據(jù)(自備),與本程序放在同一目錄下with open("./static" + path_info, "rb") as f:# 讀出文件數(shù)據(jù)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_bodyclient_socket.send(response_data.encode())else:# 響應(yīng)行 響應(yīng)頭 \r\n 響應(yīng)體# 響應(yīng)行response_line = "HTTP/1.1 200 OK\r\n"# 響應(yīng)頭response_header = "Server: PythonServer1.0\r\n"# 響應(yīng)體request_body = ret# 報(bào)文拼接data = (response_line + response_header + "\r\n").encode() + request_body# 發(fā)送client_socket.send(data)finally:# 關(guān)閉client_socket.close()if __name__ == '__main__':# 創(chuàng)建套接字server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 地址重用(1.設(shè)置 0.取消)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 綁定端口server_socket.bind(("", 8888))# 監(jiān)聽server_socket.listen(128)while True:# 取出一個(gè)客戶端套接字用以通信client_socket, client_address = server_socket.accept()print("接收到來自客戶端%s的請(qǐng)求" % str(client_address))# request_handler(client_socket)# 為每個(gè)客戶端請(qǐng)求的執(zhí)行都創(chuàng)建一個(gè)線程# 創(chuàng)建進(jìn)程pro = multiprocessing.Process(target=request_handler, args=(client_socket,))pro.start()# 關(guān)閉在父進(jìn)程的套接字,因?yàn)樵谧舆M(jìn)程中使用這個(gè)套接字,而父進(jìn)程中已經(jīng)不需要了# 父進(jìn)程和子進(jìn)程中共有兩個(gè)對(duì)象 引用底層的套接字資源 為了讓套接字正常使用client_socket.close() 復(fù)制代碼web服務(wù)器-面向?qū)ο?/h3> import socket
import multiprocessingclass HTTPServer(object):def __init__(self):"""創(chuàng)建服務(wù)器相關(guān)資源"""# 創(chuàng)建套接字server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 地址重用(1.設(shè)置 0.取消)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 綁定端口server_socket.bind(("", 8888))# 監(jiān)聽server_socket.listen(128)self.server_socket = server_socketdef request_handler(self, client_socket):"""專門來處理客戶端請(qǐng)求的函數(shù)"""# 接收用戶請(qǐng)求recv_data = client_socket.recv(1024)if not recv_data:print("客戶端已斷開連接")client_socket.close()return# 解碼數(shù)據(jù)recv_str_data = recv_data.decode()# 切割請(qǐng)求數(shù)據(jù)-->列表,取第0個(gè)元素 GET /index2.html HTTP/1.1\r\nrequest_line = recv_str_data.split("\r\n")[0]# 再次切割 取列表第一個(gè)元素 就是用戶路徑 /index2.htmlpath_info = request_line.split(" ")[1]if path_info == "/":path_info = "/index.html"try:# # 嘗試打開用戶需要的文件, 不存在則拋出異常# f = open("./static" + path_info, "rb")# # 如果文件較大 容易產(chǎn)生隱患# # 讀出文件數(shù)據(jù)# ret = f.read()# f.close()# with 語句 自動(dòng)將對(duì)象的資源驚醒釋放--> 上下文管理# 支持的數(shù)據(jù)資源有文件 socket 互斥鎖等# static文件夾為你訪問的數(shù)據(jù)(自備),與本程序放在同一目錄下with open("./static" + path_info, "rb") as f:# 讀出文件數(shù)據(jù)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_bodyclient_socket.send(response_data.encode())else:# 響應(yīng)行 響應(yīng)頭 \r\n 響應(yīng)體# 響應(yīng)行response_line = "HTTP/1.1 200 OK\r\n"# 響應(yīng)頭response_header = "Server: PythonServer1.0\r\n"# 響應(yīng)體request_body = ret# 報(bào)文拼接data = (response_line + response_header + "\r\n").encode() + request_body# 發(fā)送client_socket.send(data)finally:# 關(guān)閉client_socket.close()def start(self):while True:# 取出一個(gè)客戶端套接字用以通信client_socket, client_address = self.server_socket.accept()print("接收到來自客戶端%s的請(qǐng)求" % str(client_address))# request_handler(client_socket)# 為每個(gè)客戶端請(qǐng)求的執(zhí)行都創(chuàng)建一個(gè)線程# 創(chuàng)建進(jìn)程pro = multiprocessing.Process(target=self.request_handler, args=(client_socket,))pro.start()# 關(guān)閉在父進(jìn)程的套接字,因?yàn)樵谧舆M(jìn)程中使用這個(gè)套接字,而父進(jìn)程中已經(jīng)不需要了# 父進(jìn)程和子進(jìn)程中共有兩個(gè)對(duì)象 引用底層的套接字資源 為了讓套接字正常使用client_socket.close()if __name__ == '__main__':# 創(chuàng)建一個(gè)web服務(wù)器實(shí)例對(duì)象hs = HTTPServer()# 調(diào)用實(shí)例方法hs.start()復(fù)制代碼web服務(wù)器-協(xié)程
from gevent import monkeymonkey.patch_all()
import gevent
import socketclass HTTPServer(object):def __init__(self):"""創(chuàng)建服務(wù)器相關(guān)資源"""# 創(chuàng)建套接字server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 地址重用(1.設(shè)置 0.取消)server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 綁定端口server_socket.bind(("", 8888))# 監(jiān)聽server_socket.listen(128)self.server_socket = server_socketdef request_handler(self, client_socket):"""專門來處理客戶端請(qǐng)求的函數(shù)"""# 接收用戶請(qǐng)求recv_data = client_socket.recv(1024)if not recv_data:print("客戶端已斷開連接")client_socket.close()return # 解碼數(shù)據(jù)recv_str_data = recv_data.decode()# 切割請(qǐng)求數(shù)據(jù)-->列表,取第0個(gè)元素 GET /index2.html HTTP/1.1\r\nrequest_line = recv_str_data.split("\r\n")[0]# 再次切割 取列表第一個(gè)元素 就是用戶路徑 /index2.htmlpath_info = request_line.split(" ")[1]if path_info == "/":path_info = "/index.html"try:# # 嘗試打開用戶需要的文件, 不存在則拋出異常# f = open("./static" + path_info, "rb")# # 如果文件較大 容易產(chǎn)生隱患# # 讀出文件數(shù)據(jù)# ret = f.read()# f.close()# with 語句 自動(dòng)將對(duì)象的資源驚醒釋放--> 上下文管理# 支持的數(shù)據(jù)資源有文件 socket 互斥鎖等# static文件夾為你訪問的數(shù)據(jù)(自備),與本程序放在同一目錄下with open("./static" + path_info, "rb") as f:# 讀出文件數(shù)據(jù)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_bodyclient_socket.send(response_data.encode())else:# 響應(yīng)行 響應(yīng)頭 \r\n 響應(yīng)體# 響應(yīng)行response_line = "HTTP/1.1 200 OK\r\n"# 響應(yīng)頭response_header = "Server: PythonServer1.0\r\n"# 響應(yīng)體request_body = ret# 報(bào)文拼接data = (response_line + response_header + "\r\n").encode() + request_body# 發(fā)送client_socket.send(data)finally:# 關(guān)閉client_socket.close()def start(self):while True:# 取出一個(gè)客戶端套接字用以通信client_socket, client_address = self.server_socket.accept()print("接收到來自客戶端%s的請(qǐng)求" % str(client_address))# 創(chuàng)建并執(zhí)行協(xié)程gevent.spawn(self.request_handler, client_socket)if __name__ == '__main__':# 創(chuàng)建一個(gè)web服務(wù)器實(shí)例對(duì)象hs = HTTPServer()# 調(diào)用實(shí)例方法hs.start()復(fù)制代碼web服務(wù)器-命令行參數(shù)控制端口
from gevent import monkey
monkey.patch_all()
import socket
import gevent
import sysclass HTTPServer(object):def __init__(self,port):"""創(chuàng)建服務(wù)器相關(guān)的資源 """# 創(chuàng)建服務(wù)器套接字server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)# 為了防止服務(wù)器不能立馬重新使用相應(yīng)的端口 設(shè)置套接字地址重用選項(xiàng) 1設(shè)置 0取消server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)# 綁定server_socket.bind(('', port))# 監(jiān)聽server_socket.listen(128)self.server_socket = server_socketdef request_handler(self, client_socket):"""專門用來處理客戶端請(qǐng)求的函數(shù)"""# 接收用戶請(qǐng)求recv_data = client_socket.recv(4096)if not recv_data:print("客戶端已經(jīng)斷開連接")client_socket.close()return # 如果客戶端已經(jīng)斷開連接 則不需要再執(zhí)行后續(xù)代碼 直接結(jié)束函數(shù)即可# 解碼數(shù)據(jù)recv_str_data = recv_data.decode()# 切割請(qǐng)求數(shù)據(jù) ----> 列表data_list = recv_str_data.split('\r\n')# print(data_list)# 列表 中的第0個(gè)元素就是請(qǐng)求行 GET /index.html HTTP/1.1request_line = data_list[0]# print(request_line)# 請(qǐng)求行中的 切割出來的列表中的第一個(gè)元素就是用戶的請(qǐng)求路徑path_info = request_line.split(" ")[1]# /index.html /home/python/1.txt 直接使用系統(tǒng)的根目錄存放數(shù)據(jù)容易引起數(shù)據(jù)安全問題# 在用戶請(qǐng)求的路徑前 加上一個(gè)指定路徑 這樣當(dāng)用戶訪問的時(shí)候就會(huì)訪問指定目錄下的數(shù)據(jù) 防止服務(wù)器其他數(shù)據(jù)被竊取# ./static + /index.htmlprint(path_info)# 當(dāng)用戶只輸入域名(IP) + [端口] 用戶請(qǐng)求路徑是/if path_info == '/':path_info = '/index.html'try:# # 嘗試打開用戶需要的文件 如果文件不存在則拋出異常# file = open("./static" + path_info, "rb")# # 如果文件比較大 容易產(chǎn)生隱患## # 讀出文件數(shù)據(jù)# file_data = file.read()## file.close()# with語句 自動(dòng)將對(duì)象的資源進(jìn)行釋放 ----> 上下文管理器# 支持的數(shù)據(jù)資源 有文件 socket 互斥鎖等# static文件夾為你訪問的數(shù)據(jù)(自備),與本程序放在同一目錄下with open("./static" + path_info, "rb") as file:# 讀出文件數(shù)據(jù)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_bodyclient_socket.send(response_data.encode())else:# 響應(yīng)行 響應(yīng)頭 \r\n 響應(yīng)體# 響應(yīng)行response_line = "HTTP/1.1 200 OK\r\n"# 響應(yīng)頭response_header = "Server: PythonServer2.0\r\n"# 響應(yīng)體 就是瀏覽器收到的文件數(shù)據(jù)response_body = file_data# 按照HTTP響應(yīng)報(bào)文格式 進(jìn)行拼接response_data = (response_line + response_header + "\r\n").encode() + response_body# 發(fā)送響應(yīng)報(bào)文 send不一定能夠全部發(fā)送完成 sendall能夠保證全部發(fā)送完成# client_socket.send(response_data)client_socket.sendall(response_data)finally:# 斷開連接client_socket.close()def start(self):while True:# 取出一個(gè)客戶端套接字用以通信client_socket, client_addr = self.server_socket.accept()print("接受到來自%s的連接請(qǐng)求" % str(client_addr))# 為每個(gè)客戶端請(qǐng)求的執(zhí)行 都創(chuàng)建一個(gè)線程# request_handler(client_socket)# 創(chuàng)建并且執(zhí)行 協(xié)程gevent.spawn(self.request_handler, client_socket)def main():# python3 web.py 端口號(hào)# sys.argv是一個(gè)列表 每個(gè)元素都是一個(gè)字符串if len(sys.argv) != 2:print("參數(shù)錯(cuò)誤")return# print(sys.argv)port = sys.argv[1]if not port.isdigit():print("端口號(hào)應(yīng)該是數(shù)字")returnport_number = int(port)# 創(chuàng)建一個(gè)web服務(wù)器實(shí)例httpserver = HTTPServer(port_number)# 啟動(dòng)web服務(wù)器 的運(yùn)行httpserver.start()if __name__ == '__main__':main()復(fù)制代碼
總結(jié)
- 上一篇: 快应用quickapp快速入门教程 by
- 下一篇: 正则表达式与扩展正则表达式区别