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