简单的Web Server
import socket eol1 = b'\n\n' eol2 = b'\n\r\n' body = '''Hello,world!<h1>tszrwyx</h1>''' response_params = ['HTTP/1.0 200OK', 'Date:Sun,27 may 2018 01:01:01 GMT', 'Content-Type:text/plain;charset=utf-8', 'Content-Length:{}\r\n.format(len(body.encode()))', body] response = '\r\n'.join(response_params) def handle_connection(conn, addr): print('oh,new conn',conn,addr) import time time.sleep(100) request = b'' while((eol1 not in request)and(eol2 not in request)): request += conn.recv(1024) print(request) conn.send(response.encode()) #response转为bytes后传输 conn.close() def main(): #socket.AF_INET用于服务器与服务器之间的网络通信 #socket.SOCK_STREAM用于基于TCP的流式socket通信 serversocket = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #设置端口可复用,保证我们每次按Ctrl+C组合键之后,快速重启 serversocket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) serversocket.bind(('127.0.0.1',8000)) serversocket.listen(5)#设置backlog-socket连接最大排队数量 print('http://127.0.0.1:8000') try: while(True): conn,address = serversocket.accept() handle_connection(conn,address) finally: serversocket.close() if __name__=='__main__': main()
多线程版的WEB SERVER
# coding:utf-8 import time import errno import socket import threading EOL1 = b'\n\n' EOL2 = b'\n\r\n' body = '''Hello, world! <h1> from the5fire</h1> - from {thread_name}''' response_params = [ 'HTTP/1.0 200 OK', 'Date: Sun, 27 may 2018 01:01:01 GMT', 'Content-Type: text/plain; charset=utf-8', 'Content-Length: {length}\r\n', body, ] response = '\r\n'.join(response_params) def handle_connection(conn, addr): print(conn, addr) # time.sleep(60) request = b"" while EOL1 not in request and EOL2 not in request: request += conn.recv(1024) print(request) current_thread = threading.currentThread() content_length = len(body.format(thread_name=current_thread.name).encode()) print(current_thread.name) conn.send(response.format(thread_name=current_thread.name, length=content_length).encode()) conn.close() def main(): # socket.AF_INET 用于服务器与服务器之间的网络通信 # socket.SOCK_STREAM 基于TCP的流式socket通信 serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置端口可复用,保证我们每次Ctrl C之后,快速再次重启 serversocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serversocket.bind(('127.0.0.1', 8000)) # 可参考:https://stackoverflow.com/questions/2444459/python-sock-listen serversocket.listen(10) print('http://127.0.0.1:8000') serversocket.setblocking(1) # 设置socket为非阻塞模式 try: i = 0 while True: try: conn, address = serversocket.accept() except socket.error as e: if e.args[0] != errno.EAGAIN: raise continue i += 1 print(i) t = threading.Thread(target=handle_connection, args=(conn, address), name='thread-%s' % i) t.start() finally: serversocket.close() if __name__ == '__main__': main()
简单的WSGI application
WSGI协议分为两部分,其中一部分是Web Server或者Gateway,就像上面的代码一样,监听在某个端口上,接受外部的请求。另外一部分是Web Application,Web Server接受到请求之后会通过WSGI协议规定的方式把数据传递给Web Application,我们在Web Application中处理完之后,设置对应的状态和HEADER,之后返回body部分。Web Server拿到返回数据之后,再进行HTTP协议的封装,最终返回完整的HTTP Response数据。
# coding:utf-8 #这就是一个简单的application def simple_app(environ, start_response): status = '200 OK' response_headers = [('Content-type', 'text/plain')] start_response(status, response_headers) return ['Hello world! -by the5fire \n']
# coding:utf-8 #运行application import os import sys def run_with_cgi(application): environ = dict(os.environ.items()) environ['wsgi.input'] = sys.stdin environ['wsgi.errors'] = sys.stderr environ['wsgi.version'] = (1, 0) environ['wsgi.multithread'] = False environ['wsgi.multiprocess'] = True environ['wsgi.run_once'] = True if environ.get('HTTPS', 'off') in ('on', '1'): environ['wsgi.url_scheme'] = 'https' else: environ['wsgi.url_scheme'] = 'http' headers_set = [] headers_sent = [] def write(data): #如果headers_set是空的话就抛出下面这个异常 if not headers_set: raise AssertionError("write() before start_response()") elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set sys.stdout.write('Status: %s\r\n' % status) for header in response_headers: sys.stdout.write('%s: %s\r\n' % header) sys.stdout.write('\r\n') sys.stdout.write(data) sys.stdout.flush() def start_response(status, response_headers, exc_info=None): if exc_info: try: # Re-raise original exception if headers sent if headers_sent: raise [exc_info[0],exc_info[1],exc_info[2]] finally: exc_info = None # avoid dangling circular ref elif headers_set: raise AssertionError("Headers already set!") headers_set[:] = [status, response_headers] return write result = application(environ, start_response) try: for data in result: if data: # don't send headers until body appears write(data) if not headers_sent: write('') # send headers now if body was empty finally: if hasattr(result, 'close'): result.close() if __name__ == '__main__': run_with_cgi(simple_app)
WSGI协议规定,application必须是一个callable对象,这意味这个对象可以是Python中的一个函数,也可以是一个实现了__call__方法的类的实例。比如这个: class AppClass(object): status = '200 OK' response_headers = [('Content-type', 'text/plain')] def __call__(self, environ, start_response): print(environ, start_response) start_response(self.status, self.response_headers) return ['Hello AppClass.__call__\n'] application = AppClass()
正在更新中...