新手实现的 Python web 框架的代码在 win7 运行报错, Ubuntu 正常运行,求助大佬

2018-05-21 19:55:10 +08:00
 taoing

服务器代码:

import socket
from multiprocessing import Process
import re

class HTTPServer(object):
    def __init__(self, application):
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.app = application
    def bind(self, port):
        print('port:',port)
        self.server_socket.bind(('', port))
    def start(self):
        self.server_socket.listen(128)
        print('HTTP server is running...')

        while True:
            conn_socket, client_addr = self.server_socket.accept()
            print('connection from %s : %s' % client_addr)
            # 创建新进程处理客户端连接
            p = Process(target = self.handle_request, args = (conn_socket,))
            p.start()
            conn_socket.close()
    def start_response(self, status, headers):
        server_headers = [
        ('Server', 'MyWebServer 1.0')
        ]
        server_headers = headers + server_headers
        # 构造响应首部行
        response_headers = 'HTTP/1.1 ' + status + '\r\n'
        for header in server_headers:
            response_headers = response_headers + '%s:%s' % header + '\r\n'
        self.response_headers = response_headers

    def handle_request(self, conn_socket):
        '''处理客户端请求'''
        env = {}
        request_data = conn_socket.recv(2048).decode('utf-8')
        print('request from client:')
        print(request_data)
        '''解析请求返回响应'''
        # 请求行
        reuqestmethodline = request_data.split('\r\n')[0]
        # 请求方法
        requestmethod = reuqestmethodline.split(' ', 1)[0]
        # 请求资源
        requestpath = re.match(r'\w+\s+(/[a-zA-Z0-9\_\.]*)',reuqestmethodline).group(1)
        env['Method'] = requestmethod
        env['PATH_INFO'] = requestpath
        # 返回响应体
        response_body = self.app(env, self.start_response)
        response = self.response_headers + '\r\n' + response_body
        print('response from server:')
        print(response)
        conn_socket.send(response.encode('utf-8'))
        conn_socket.close()

web 框架代码:

import time
from mywebserver import HTTPServer

class Application(object):
    # 框架的核心部分
    def __init__(self, urls):
        self.urls = urls

    def __call__(self, env, start_response):
        path = env.get('PATH_INFO', '/')
        for url, handler in self.urls:
            if path == url:
                response_body = handler(env, start_response)
                return response_body
        # 请求路径不存在,返回 404 响应码
        status = '404 Not Found'
        headers = [('Content-Type', 'text/html')]
        start_response(status, headers)
        response_body = 'The file not found!'
        return response_body

def ctime(env, start_response):
    status = '200 OK'
    headers = [('Content-Type', 'text/html')]
    start_response(status, headers)
    return time.ctime()

def hello(env, start_response):
    status = '200 OK'
    headers = [('Content-Type', 'text/html')]
    start_response(status, headers)
    return 'Hello, World!'

urls = [
('/', hello),
('/ctime', ctime),
('/hello', hello)
]
app = Application(urls)
http_server = HTTPServer(app)
http_server.bind(8000)
http_server.start()

在 win7 python3.5.2 上运行报错:

λ python mywebframe.py
port: 8000
HTTP server is running...
connection from 127.0.0.1 : 50094
connection from 127.0.0.1 : 50095
port: 8000
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "C:\Users\taomian\AppData\Local\Programs\Python\Python35\lib\multiprocessing\spawn.py", line 106, in spawn_main
    exitcode = _main(fd)
  File "C:\Users\taomian\AppData\Local\Programs\Python\Python35\lib\multiprocessing\spawn.py", line 115, in _main
    prepare(preparation_data)
  File "C:\Users\taomian\AppData\Local\Programs\Python\Python35\lib\multiprocessing\spawn.py", line 226, in prepare
    _fixup_main_from_path(data['init_main_from_path'])
  File "C:\Users\taomian\AppData\Local\Programs\Python\Python35\lib\multiprocessing\spawn.py", line 278, in _fixup_main_from_path
    run_name="__mp_main__")
  File "C:\Users\taomian\AppData\Local\Programs\Python\Python35\lib\runpy.py", line 254, in run_path
    pkg_name=pkg_name, script_name=fname)
  File "C:\Users\taomian\AppData\Local\Programs\Python\Python35\lib\runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "C:\Users\taomian\AppData\Local\Programs\Python\Python35\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "D:\Documents\python\code\2.2 wsgi_server\mywebframe.py", line 40, in <module>
port: 8000
    http_server.bind(8000)
Traceback (most recent call last):
  File "D:\Documents\python\code\2.2 wsgi_server\mywebserver.py", line 11, in bind
  File "<string>", line 1, in <module>
  File "C:\Users\taomian\AppData\Local\Programs\Python\Python35\lib\multiprocessing\spawn.py", line 106, in spawn_main
    self.server_socket.bind(('', port))
OSError: [WinError 10048] 通常每个套接字地址(协议 /网络地址 /端口)只允许使用一次。

在 ubuntu 上 python3.5.2 正常运行:

allen@ubuntu:~/test/code$ python3 mywebframe.py 
port: 8000
HTTP server is running...
connection from 127.0.0.1 : 45618
request from client:
GET / HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1


response from server:
HTTP/1.1 200 OK
Content-Type:text/html
Server:MyWebServer 1.0

Hello, World!
connection from 127.0.0.1 : 45620
request from client:
GET /favicon.ico HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive


response from server:
HTTP/1.1 404 Not Found
Content-Type:text/html
Server:MyWebServer 1.0

The file not found!

2650 次点击
所在节点    Python
12 条回复
taoing
2018-05-21 20:04:09 +08:00
在 win7 上看报错提示,我理解是端口 8000 被绑定了两次导致出错,不知道为什么会出现这种情况,想请教大佬可以给我解答。
ycfung
2018-05-21 20:05:32 +08:00
你这代码贴得太可怕了…
wwqgtxx
2018-05-21 20:05:47 +08:00
在 windows 下不要用“创建新进程处理客户端连接”这种方式,会出各种诡异的问题,应该使用“新线程”
wwqgtxx
2018-05-21 20:07:54 +08:00
另外这三行代码
http_server = HTTPServer(app)
http_server.bind(8000)
http_server.start()
应该包裹在
if __name__ == '__main__':
中,否则容易出现重复 start 你的 http_server 的情况
taoing
2018-05-21 20:08:19 +08:00
@wwqgtxx 好,我试试用线程看看
DevNet
2018-05-21 20:10:25 +08:00
可能是前一次运行已经占用了这个端口,然后一直没释放? kill 试试,
或者管理员权限问题?
wwqgtxx
2018-05-21 20:10:38 +08:00
根本原因只在于 windows 不支持 fork 模式,他的 process 是重新起一个新的 Python.exe 实现的,所以会再次 import 一次你的 mywebframe.py,而不过你没有把启动代码包裹在 if __name__ == '__main__': 中就会导致这一段代码再一次在子进程中被执行
taoing
2018-05-21 20:13:12 +08:00
@wwqgtxx 谢谢你的解答,原来系统间有差异,然后试了 if __name__ == '__main__':就没有报错了
iConnect
2018-05-21 20:21:55 +08:00
如果你生产环境是 Ubuntu,就不用管 win 上报错了,我们经理都要求所有人环境统一,减少系统差异带来额外的 bug
taoing
2018-05-21 20:31:14 +08:00
@iConnect 我是个新手在学,只好在自己电脑上试
so1n
2018-05-21 21:04:16 +08:00
用 linux 吧,win 不能 fork 也没有 epoll 事件循环
lidongyx
2018-05-21 23:45:15 +08:00
学技术就不要在 windows 环境下折腾了,你折腾出来的这点经验都是浪费时间,因为生产实践中还是要用 linux 的,用虚拟机或者开发板、云服务器、双系统吧

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/456621

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX