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()

 

posted @ 2020-04-01 14:38  olivertian  阅读(1303)  评论(0编辑  收藏  举报