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