平时我们开发web大部分情况下直接使用框架现拉的一个底层,今天我们来徒手撸一个简单的web服务器程序,通过这个简单的示例让你对框架是如何做到有更深的理解。
python自带静态web服务器
其实python给我们自带了一个静态web服务器,我们使用命令行随便进入到一个有静态文件的目录中,运行如下命令:
1 2
| Tony-iMac:diandian_blog tony$ python3 -m http.server 8001 Serving HTTP on :: port 8001 (http://[::]:8001/) ...
|
-m选项说明:
-m表示运行包里面的模块,执行这个命令的时候,需要进入你自己指定静态文件的目录,然后通过浏览器就能访问对应的 html文件了,这样一个静态的web服务器就搭建好了。
此时访问浏览器
![]()
- 静态Web服务器是为发出请求的浏览器提供静态文档的程序,
- 搭建Python自带的Web服务器使用python3 –m http.server 端口号 这个命令即可,端口号不指定默认是8000
开发自己的静态Web服务器
在上一篇TCP网络应用程序开发流程回顾中,我们已经回顾了网络应用的开发流程,知道了HTTP协议本质上就是基于TCP,只不过http是一个通信一次即断开的TCP,相较于之前的交互型TCP应用是应该是更简单的。
我们这里只需要写一套服务端socket即可,浏览器是一个天生的客户端,代码中也包含了详细的注释,故也不在其他地方做解释。
响应固定页面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
|
import socket
socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
socket_server.bind(('localhost', 9999))
socket_server.listen(3) print("服务端开始运行了……")
while True: client_socket, ip_port = socket_server.accept() print(ip_port, '连接上线了') recv_data = client_socket.recv(4096) recv_data_length = len(recv_data) if recv_data_length == 0: client_socket.close() print(ip_port, '断开了与服务器的链接') response_line = 'HTTP/1.1 200 OK\r\n' response_header = 'Server: PWS1.0\r\n' empty_line = '\r\n' response_body = '<!DOCTYPE HTML><html><head><meta charset="UTF-8"><title>我是标题</title></head><body><h1>我是内容</h1></body></html>' response_data = (response_line+response_header+empty_line+response_body).encode('utf8') client_socket.send(response_data) client_socket.close()
|
注:以上响应体response_body我们使用的html代码,如果内容过多可直接使用with open打开html文件访问,此处简单演示,故不作文件打开操作
响应指定页面(进阶)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
|
import socket
socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
socket_server.bind(('localhost', 9999))
socket_server.listen(3) print("服务端开始运行了……")
while True: client_socket, ip_port = socket_server.accept() print(ip_port, '连接上线了') recv_data = client_socket.recv(4096) recv_data_length = len(recv_data) if recv_data_length == 0: client_socket.close() print(ip_port, '断开了与服务器的链接') response_line = 'HTTP/1.1 200 OK\r\n' response_header = 'Server: PWS1.0\r\n' empty_line = '\r\n' format_data = recv_data.decode('utf8').split(' ', maxsplit=2) if format_data[1] == '/': response_body = '<!DOCTYPE HTML><html><head><meta charset="UTF-8"><title>首页</title></head><body><h1>我是首页</h1></body></html>' else: response_body = '<!DOCTYPE HTML><html><head><meta charset="UTF-8"><title>错误页</title></head><body><h1>该页面出错了</h1></body></html>' response_data = (response_line+response_header+empty_line+response_body).encode('utf8') client_socket.send(response_data) client_socket.close()
|
多任务版静态web服务器(再进阶)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
import socket import threading
def client_socket_handle(client_socket): recv_data = client_socket.recv(4096) recv_data_length = len(recv_data) if recv_data_length == 0: client_socket.close() response_line = 'HTTP/1.1 200 OK\r\n' response_header = 'Server: PWS1.0\r\n' empty_line = '\r\n' format_data = recv_data.decode('utf8').split(' ', maxsplit=2) print(format_data) if format_data[1] == '/': response_body = '<!DOCTYPE HTML>' \ '<html>' \ '<head>' \ '<meta charset="UTF-8">' \ '<title>首页</title>' \ '</head>' \ '<body><h1>我是首页</h1></body>' \ '</html>' else: response_body = '<!DOCTYPE HTML><html>' \ '<head>' \ '<meta charset="UTF-8">' \ '<title>错误页</title>' \ '</head>' \ '<body><h1>该页面出错了</h1></body>' \ '</html>' response_data = (response_line + response_header + empty_line + response_body).encode('utf8') client_socket.send(response_data) client_socket.close()
def main(): socket_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) socket_server.bind(('localhost', 9999)) socket_server.listen(3) print("服务端开始运行了……") while True: client_socket, ip_port = socket_server.accept() print(ip_port, '连接上线了') main_thread = threading.Thread(target=client_socket_handle, args=(client_socket,)) main_thread.setDaemon(True) main_thread.start()
if __name__ == '__main__': main()
|
面向对象版静态web服务器(继续进阶)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
import socket import threading
class HttpServer(object): """面向对象静态web服务器""" def __init__(self): self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.server_socket.bind(('', 9999)) self.server_socket.listen(128) print("服务端开始运行了……")
@staticmethod def client_socket_handle(client_socket): recv_data = client_socket.recv(4096) recv_data_length = len(recv_data) if recv_data_length == 0: client_socket.close() response_line = 'HTTP/1.1 200 OK\r\n' response_header = 'Server: PWS1.0\r\n' empty_line = '\r\n' format_data = recv_data.decode('utf8').split(' ', maxsplit=2) print(format_data) if format_data[1] == '/': response_body = '<!DOCTYPE HTML>' \ '<html>' \ '<head>' \ '<meta charset="UTF-8">' \ '<title>首页</title>' \ '</head>' \ '<body><h1>我是首页</h1></body>' \ '</html>' else: response_body = '<!DOCTYPE HTML><html>' \ '<head>' \ '<meta charset="UTF-8">' \ '<title>错误页</title>' \ '</head>' \ '<body><h1>该页面出错了</h1></body>' \ '</html>' response_data = (response_line + response_header + empty_line + response_body).encode('utf8') client_socket.send(response_data) client_socket.close()
def main(self): while True: client_socket, ip_port = self.server_socket.accept() print(ip_port, '连接上线了') main_thread = threading.Thread(target=self.client_socket_handle, args=(client_socket,)) main_thread.setDaemon(True) main_thread.start()
if __name__ == '__main__': http_server = HttpServer() http_server.main()
|
命令行启动静态web服务器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
|
import socket import sys import threading
class HttpServer(object): """面向对象静态web服务器""" def __init__(self, port=9998): self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True) self.server_socket.bind(('', port)) self.server_socket.listen(128) print("服务端开始运行了……")
@staticmethod def client_socket_handle(client_socket): recv_data = client_socket.recv(4096) recv_data_length = len(recv_data) if recv_data_length == 0: client_socket.close() response_line = 'HTTP/1.1 200 OK\r\n' response_header = 'Server: PWS1.0\r\n' empty_line = '\r\n' format_data = recv_data.decode('utf8').split(' ', maxsplit=2) print(format_data) if format_data[1] == '/': response_body = '<!DOCTYPE HTML>' \ '<html>' \ '<head>' \ '<meta charset="UTF-8">' \ '<title>首页</title>' \ '</head>' \ '<body><h1>我是首页</h1></body>' \ '</html>' else: response_body = '<!DOCTYPE HTML><html>' \ '<head>' \ '<meta charset="UTF-8">' \ '<title>错误页</title>' \ '</head>' \ '<body><h1>该页面出错了</h1></body>' \ '</html>' response_data = (response_line + response_header + empty_line + response_body).encode('utf8') client_socket.send(response_data) client_socket.close()
def start(self): while True: client_socket, ip_port = self.server_socket.accept() print(ip_port, '连接上线了') main_thread = threading.Thread(target=self.client_socket_handle, args=(client_socket,)) main_thread.setDaemon(True) main_thread.start()
def main(): shell_argvs = sys.argv if len(shell_argvs) != 2: print("启动命令如下: python3 xxx.py 9090") return False if not shell_argvs[1].isdigit(): print("端口必须为数字") return False http_server = HttpServer(int(shell_argvs[1])) http_server.start()
if __name__ == '__main__': main()
|
到这里我们其实已经明白了Django怎么使用一行命令就把服务给启动起来了,看到我们这里的简化版本,原来也就这么简单。