短連接是客戶端每請求一個資源就需要進行tcp的三次握手和四次揮手,長連接是一次握手連接后,只要不斷開連接,中間可多次發送數據,客戶端和服務器頻繁握手和揮手需要占用大量的網絡資源,於是客戶端和服務器之間的連接由短連接演變為長連接
長連接需要在服務器返回數據的http頭部增加一個Content-Length屬性,告訴客戶端,你本次請求的這個資源的數據長度是多少,這樣,客戶端在收到服務器的回應后,就可以知道我要的數據服務器是否全部給我了,如果沒有,那就等待,直到服務端把全部數據發送過來。
有了Content-Length屬性,客戶端和服務端一旦連接之后就不必着急着斷開,因為只要客戶端根據Content-Length判斷本次請求的數據傳輸完畢,就可以接着發送另一個請求,這就實現了一次連接,多次請求,這也是長連接的優勢所在了,減少了每次請求每次都要連接的冗余
一個場景就是,瀏覽器打開一個網頁,只需要發起一次連接請求即可,之后無論是加載圖片請求還是js文件請求,都可以在一個連接中完成,而不需要每加載一個文件就發起一次請求,大大減少了連接次數,節省了網絡資源。對於服務端來說也有很大的好處,因為一次連接意味着需要創建一個新的套接字,如果使用短連接,那么加載一個資源就得創建很多個套接字,資源浪費很大。
import re def handle_request(handle_socket, request): print(request) request_lines = request.splitlines() # 解析 GET / HTTP/1.1 ret = re.match(r"[^/]+/([^ ]*)", request_lines[0]) if ret: file_name = ret.group(1) else: file_name = "index.html" try: f = open(".\html\\" + file_name, "rb") except Exception: response_body = "您訪問的頁面不存在".encode("utf8") else: html_content = f.read() f.close() response_body = html_content response_header = "HTTP/1.1 200 OK\r\n" response_header += "Content-Length:%s\r\n" % len(response_body) # 瀏覽器接收到這么多數據就明白本次請求完成,發送下個請求 response_header += "\r\n" response = response_header.encode("utf8") + response_body handle_socket.send(response) # handle_socket.close() 這個不要加,否則就變成短連接了 def main(): import socket tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) tcp_socket.bind(("", 7777)) tcp_socket.listen(128) tcp_socket.setblocking(False) new_socket_list = list() while True: try: new_socket, new_addr = tcp_socket.accept() except Exception as e: pass else: new_socket.setblocking(False) new_socket_list.append(new_socket) print("接收到請求") for socket in new_socket_list: try: recv_data = socket.recv(1024).decode("utf8") except Exception as e: pass else: if recv_data: handle_request(socket, recv_data) else: # recv_data為空,說明客戶端調用了close,此時該socket全部數據接收完畢,應從列表移除 socket.close() new_socket_list.remove(socket) tcp_socket.close() if __name__ == "__main__": main()
