http服務器長連接


短連接是客戶端每請求一個資源就需要進行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()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM