python3 web服务器_python3 简单web服务器
補充:tcp長連接和短連接
長連接:
客戶端向服務器發起連接請求,服務器接收到請求回應給客戶端,雙方完成三次握手,然后客戶端發送消息,服務端回應消息,每一次完成讀寫操作,套接字不不關閉,也就是連接不關閉,繼續保持連接,等待下一次的讀寫操作,長時間之后客戶端發起關閉請求。
短連接:
短連接則是一般只會在 client/server 間傳遞一次讀寫操作,一次讀寫操作之后就關閉連接,下一次的操通信則又從三次握手開始重新建立連接。
簡單的http服務器:
__author__ = 'Administrator'
importsocketdefservice_client(new_socket):#1.接收瀏覽器發送過來的請求,即http請求
request=new_socket.recv(1024)#2.返回瀏覽器http格式的數據
#2.1準備發送給瀏覽器的數據——header
#\r\n給Windows使用
response="HTTP/1.1 200 OK\r\n"response+="\r\n"
#2.2準備發送給瀏覽器的數據——body
response+="
哈哈哈哈哈
"new_socket.send(response.encode("utf-8"))#3.關閉套接字
new_socket.close()defmain():#1.創建套接字
tcp_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#2.綁定
tcp_server.bind(("",8081))#3.監聽套接字
tcp_server.listen(128)#4.等待新客戶端的鏈接
whileTrue:
new_socket,client_addr=tcp_server.accept()#5.為這個客戶端服務
service_client(new_socket)#6.關閉監聽套接字
tcp_server.close()if __name__ == '__main__':
main()
View Code
返回給瀏覽器相應的頁面:
Python splitlines() 按照行('\r', '\r\n', \n')分隔,返回一個包含各行作為元素的列表,如果參數 keepends 為 False,不包含換行符,如果為 True,則保留換行符。
str.splitlines([keepends])
keepends -- 在輸出結果里是否保留換行符('\r', '\r\n', \n'),默認為 False,不包含換行符,如果為 True,則保留換行符。
__author__ = 'Administrator'
importsocketdefservice_client(new_socket):#1.接收瀏覽器發送過來的請求,即http請求
request=new_socket.recv(1024)print("===="*100)print(request)#2.返回瀏覽器http格式的數據
#2.1準備發送給瀏覽器的數據——header
#\r\n給Windows使用
response="HTTP/1.1 200 OK\r\n"response+="\r\n"
#2.2準備發送給瀏覽器的數據——body
f=open("./html/index.html","rb")
html_content=f.read()
f.close()#將response header發送給瀏覽器
new_socket.send(response.encode("utf-8"))#將response body發送給瀏覽器
new_socket.send(html_content)#3.關閉套接字
new_socket.close()defmain():#1.創建套接字
tcp_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#2.綁定
tcp_server.bind(("",8081))#3.監聽套接字
tcp_server.listen(128)#4.等待新客戶端的鏈接
whileTrue:
new_socket,client_addr=tcp_server.accept()#5.為這個客戶端服務
service_client(new_socket)#6.關閉監聽套接字
tcp_server.close()if __name__ == '__main__':
main()
View Code
根據用戶需求返回相應的頁面(對頁面進行操作之后返回的頁面):
__author__ = 'Administrator'
importsocketimportredefservice_client(new_socket):#1.接收瀏覽器發送過來的請求,即http請求
request=new_socket.recv(1024).decode("utf-8")#print("===="*100)
#print(request)
request_lines =request.splitlines()print("")print(">>>>"*20)print(request_lines)#GET /index.html HTTP/1.1
file_name=""res=re.match(r"[^/]+(/[^ ]*)",request_lines[0])ifres:
file_name=res.group(1)if file_name=="/":
file_name="/index.html"
#2.返回瀏覽器http格式的數據
#\r\n給Windows使用
try:#忘了,復習一下
#try中是嘗試執行的代碼
#except 中是對錯誤進行處理
#else中是沒有異常才會執行的代碼
f=open("./html"+file_name,"rb")except:
response="HTTP/1.1 404 NOT FOUND\r\n"response+="\r\n"response+="————file not found————"new_socket.send(response.encode("utf-8"))else:
html_content=f.read()
f.close()
response="HTTP/1.1 200 OK\r\n"response+="\r\n"
#將response header發送給瀏覽器
new_socket.send(response.encode("utf-8"))#將response body發送給瀏覽器
new_socket.send(html_content)#3.關閉套接字
new_socket.close()defmain():#1.創建套接字
tcp_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#2.綁定
tcp_server.bind(("",8081))#3.監聽套接字
tcp_server.listen(128)#4.等待新客戶端的鏈接
whileTrue:
new_socket,client_addr=tcp_server.accept()#5.為這個客戶端服務
service_client(new_socket)#6.關閉監聽套接字
tcp_server.close()if __name__ == '__main__':
main()
View Code
使用多進程完成http服務器:
__author__ = 'Administrator'
importsocketimportreimportmultiprocessingdefservice_client(new_socket):#1.接收瀏覽器發送過來的請求,即http請求
request=new_socket.recv(1024).decode("utf-8")#print("===="*100)
#print(request)
request_lines =request.splitlines()print("")print(">>>>"*20)print(request_lines)#GET /index.html HTTP/1.1
file_name=""res=re.match(r"[^/]+(/[^ ]*)",request_lines[0])ifres:
file_name=res.group(1)if file_name=="/":
file_name="/index.html"
#2.返回瀏覽器http格式的數據
#\r\n給Windows使用
try:#忘了,復習一下
#try中是嘗試執行的代碼
#except 中是對錯誤進行處理
#else中是沒有異常才會執行的代碼
f=open("./html"+file_name,"rb")except:
response="HTTP/1.1 404 NOT FOUND\r\n"response+="\r\n"response+="————file not found————"new_socket.send(response.encode("utf-8"))else:
html_content=f.read()
f.close()
response="HTTP/1.1 200 OK\r\n"response+="\r\n"
#將response header發送給瀏覽器
new_socket.send(response.encode("utf-8"))#將response body發送給瀏覽器
new_socket.send(html_content)#3.關閉套接字
new_socket.close()defmain():#1.創建套接字
tcp_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#2.綁定
tcp_server.bind(("",8081))#3.監聽套接字
tcp_server.listen(128)whileTrue:#4.等待新客戶端的鏈接[這里類似銀行的柜臺窗口]
new_socket,client_addr=tcp_server.accept()#5.為這個客戶端服務
p=multiprocessing.Process(target=service_client,args=(new_socket,))
p.start()#在主進程創建子進程之后,子進程會復制主進程的所有資源,所有就會有兩個相同的new_socket套接字
#在service_client()中是子進程關閉了套接字,那在主進程中也是需要關閉該套接字
new_socket.close()#6.關閉監聽套接字
tcp_server.close()if __name__ == '__main__':
main()
View Code
使用多線程完成http服務器:
__author__ = 'Administrator'
importsocketimportreimportthreadingdefservice_client(new_socket):#1.接收瀏覽器發送過來的請求,即http請求
request=new_socket.recv(1024).decode("utf-8")#print("===="*100)
#print(request)
request_lines =request.splitlines()print("")print(">>>>"*20)print(request_lines)#GET /index.html HTTP/1.1
file_name=""res=re.match(r"[^/]+(/[^ ]*)",request_lines[0])ifres:
file_name=res.group(1)if file_name=="/":
file_name="/index.html"
#2.返回瀏覽器http格式的數據
#\r\n給Windows使用
try:#忘了,復習一下
#try中是嘗試執行的代碼
#except 中是對錯誤進行處理
#else中是沒有異常才會執行的代碼
f=open("./html"+file_name,"rb")except:
response="HTTP/1.1 404 NOT FOUND\r\n"response+="\r\n"response+="————file not found————"new_socket.send(response.encode("utf-8"))else:
html_content=f.read()
f.close()
response="HTTP/1.1 200 OK\r\n"response+="\r\n"
#將response header發送給瀏覽器
new_socket.send(response.encode("utf-8"))#將response body發送給瀏覽器
new_socket.send(html_content)#3.關閉套接字
new_socket.close()defmain():#1.創建套接字
tcp_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#2.綁定
tcp_server.bind(("",8081))#3.監聽套接字
tcp_server.listen(128)whileTrue:#4.等待新客戶端的鏈接
new_socket,client_addr=tcp_server.accept()#5.為這個客戶端服務
p=threading.Thread(target=service_client,args=(new_socket,))
p.start()#注意:這里和進程的區別,多線程之間共享變量,子線程沒有復制主線程
#new_socket.close()
#6.關閉監聽套接字
tcp_server.close()if __name__ == '__main__':
main()
View Code
使用gevent(協程)完成http服務器:
__author__ = 'Administrator'
importsocketimportreimportgeventfrom gevent importmonkey
monkey.patch_all()defservice_client(new_socket):#1.接收瀏覽器發送過來的請求,即http請求
request=new_socket.recv(1024).decode("utf-8")#print("===="*100)
#print(request)
request_lines =request.splitlines()print("")print(">>>>"*20)print(request_lines)#GET /index.html HTTP/1.1
file_name=""res=re.match(r"[^/]+(/[^ ]*)",request_lines[0])ifres:
file_name=res.group(1)if file_name=="/":
file_name="/index.html"
#2.返回瀏覽器http格式的數據
#\r\n給Windows使用
try:#忘了,復習一下
#try中是嘗試執行的代碼
#except 中是對錯誤進行處理
#else中是沒有異常才會執行的代碼
f=open("./html"+file_name,"rb")except:
response="HTTP/1.1 404 NOT FOUND\r\n"response+="\r\n"response+="————file not found————"new_socket.send(response.encode("utf-8"))else:
html_content=f.read()
f.close()
response="HTTP/1.1 200 OK\r\n"response+="\r\n"
#將response header發送給瀏覽器
new_socket.send(response.encode("utf-8"))#將response body發送給瀏覽器
new_socket.send(html_content)#3.關閉套接字
new_socket.close()defmain():#1.創建套接字
tcp_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#2.綁定
tcp_server.bind(("",8081))#3.監聽套接字
tcp_server.listen(128)whileTrue:#4.等待新客戶端的鏈接
new_socket,client_addr=tcp_server.accept()#5.為這個客戶端服務
gevent.spawn(service_client,new_socket)#6.關閉監聽套接字
tcp_server.close()if __name__ == '__main__':
main()
View Code
單進程、線程、非堵塞實現并發:
__author__ = 'Administrator'
importsocket
tcp_socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
tcp_socket.bind(("",8081))
tcp_socket.listen(128)#設置套接字為非堵塞方式
tcp_socket.setblocking(False)
client_list=list()#在沒有設置套接字為堵塞的時候,accept和recv默認都是堵塞的,那客戶端沒有發送鏈接或者沒有發送數據過來都是不會報異常的,#現在設置套接字為非堵塞,那么此時accept就是非堵塞的,那客戶端沒有發送鏈接或者沒有發送數據過來都是報異常的,
whileTrue:try:
new_tcp_socket,addr=tcp_socket.accept()exceptException as res:print(res)print("————沒有新的客戶端鏈接————")else:#設置新的套接字為非堵塞,默認堵塞的時候,不發數據過來不會異常,但是此時非堵塞不發數據過來就會異常
new_tcp_socket.setblocking(False)
client_list.append(new_tcp_socket)for client_socket inclient_list:try:
recv_data=new_tcp_socket.recv(1024)exceptException as res:print(res)print("————客戶端沒有發送數據過來————")else:print(recv_data)ifrecv_data:print("————客戶端發送數據過來————")else:
client_list.remove(new_tcp_socket)
new_tcp_socket.close()print("————客戶端已經關閉了————")
View Code
單進程、線程、非堵塞、長連接實現http服務器:
__author__ = 'Administrator'
importsocketimportredefservice_client(new_socket,request):#1.接收瀏覽器發送過來的請求,即http請求
#request=new_socket.recv(1024).decode("utf-8")
#print("===="*100)
#print(request)
request_lines =request.splitlines()print("")print(">>>>"*20)print(request_lines)#GET /index.html HTTP/1.1
file_name=""res=re.match(r"[^/]+(/[^ ]*)",request_lines[0])ifres:
file_name=res.group(1)if file_name=="/":
file_name="/index.html"
#2.返回瀏覽器http格式的數據
#\r\n給Windows使用
try:#忘了,復習一下
#try中是嘗試執行的代碼
#except 中是對錯誤進行處理
#else中是沒有異常才會執行的代碼
f=open("./html"+file_name,"rb")except:
response="HTTP/1.1 404 NOT FOUND\r\n"response+="\r\n"response+="————file not found————"new_socket.send(response.encode("utf-8"))else:
html_content=f.read()
f.close()
response_body=html_content
response_header= "HTTP/1.1 200 OK\r\n"response_header="Content-Length:%d\r\n" %len(response_body)
response_header+="\r\n"response=response_header.encode("utf-8")+response_body#將response 發送給瀏覽器
new_socket.send(response)#3.關閉套接字
#在這個地方服務器強制關閉了套接字,表明了并不是長連接,而是短連接
#new_socket.close()
defmain():#1.創建套接字
tcp_server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#2.綁定
tcp_server.bind(("",8081))#3.監聽套接字
tcp_server.listen(128)
tcp_server.setblocking(False)#將套接字設置為非堵塞
client_list=list()#4.等待新客戶端的鏈接
whileTrue:try:
new_socket,client_addr=tcp_server.accept()exceptException as res:pass
else:
new_socket.setblocking(False)
client_list.append(new_socket)for client_socket inclient_list:try:
recv_data= client_socket.recv(1024).decode("utf-8")exceptException as res:pass
else:ifrecv_data:
service_client(client_socket,recv_data)else:
client_socket.close()
client_list.remove(client_socket)#6.關閉監聽套接字
tcp_server.close()if __name__ == '__main__':
main()
View Code
epoll是Linux內核為處理大批量文件描述符而作了改進的poll,是Linux下多路復用IO接口select/poll的增強版本,它能顯著提高程序在大量并發鏈接中只有少量活躍的情況下的系統CPU利用率。另一點原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入Ready隊列的描述符集合就行了。epoll除了提供select/poll那種IO事件的水平觸發(Level Triggered)外,還提供了邊緣觸發(Edge Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少epoll_wait/epoll_pwait的調用,提高應用程序效率。
通信過程:
瀏覽器訪問服務器的過程
在瀏覽器訪問http:www.baidu.com(域名),該電腦先檢查是否認識默認網關的MAC地址,如果沒有以arp廣播,
廣播過去該電腦的默認網關地址組織一個域名解析的數據請求發送給網關,網關發送到互聯網上,互聯網經過一層一層的轉發,
到達DNS服務器,其把域名解析出來之后把ip地址回送給瀏覽器,然后把ip發送給網關,網關把數據發送到互聯網,把數據轉發給服務器,
發送到服務器,客戶端和瀏覽器三次握手成功,瀏覽器把請求發送給服務器,服務器解析請求返回數據給客戶端,
瀏覽器顯示,顯示成功之后,然后四次揮手,結束。
總結
以上是生活随笔為你收集整理的python3 web服务器_python3 简单web服务器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【LeetCode笔记】剑指 Offer
- 下一篇: websocket python爬虫_p