Python提示[Errno 32]Broken pipe导致线程crash错误解决方法


Posted in Python onNovember 19, 2014

本文实例讲述了Python提示[Errno 32]Broken pipe导致线程crash错误解决方法。分享给大家供大家参考。具体方法如下:

1. 错误现象
ThreadingHTTPServer 实现的 http 服务,如果客户端在服务器返回前,主动断开连接,则服务器端会报 [Errno 32] Broken pipe 错,并导致处理线程 crash.
下面先看个例子,python 版本: 2.7
示例代码

#!/usr/bin/env python

#!coding=utf-8

  

import os

import time

import socket

import threading

from BaseHTTPServer import HTTPServer ,BaseHTTPRequestHandler

from SocketServer import ThreadingMixIn

  

class RequestHandler(BaseHTTPRequestHandler):

    def do_GET(self):

        """

        处理get请求

        """       

        query=self.path

        print "query: %s thread=%s" % (query, str(threading.current_thread()))

         

        #ret_str="<html>" + self.path + "<br>" + str(self.server) + "<br>" + str(self.responses) +  "</html>"

        ret_str="<html>" + self.path + "<br>" + str(self.server) +  "</html>"

         

        time.sleep(5)

         

        try:

            self.send_response(200)

            self.send_header('Content-type','text/html')

            self.end_headers()

            self.wfile.write(ret_str)

        except socket.error, e:

            print "socket.error : Connection broke. Aborting" + str(e)

            self.wfile._sock.close()  # close socket

            self.wfile._sock=None

            return False

        

        print "success prod query :%s" % (query)

        return True

  

#多线程处理

class ThreadingHTTPServer(ThreadingMixIn,HTTPServer):

    pass

     

if __name__ == '__main__':

    serveraddr = ('',9001)

 

    ser = ThreadingHTTPServer(serveraddr,RequestHandler)

    ser.serve_forever()

    sys.exit(0)

运行服务
./thread_http_server_error.py
第1次 curl ,等待返回
[~]$curl -s 'http://10.232.41.142:9001/hello1′

<html>/hello1<br><__main__.ThreadingHTTPServer instance at 0x37483b0></html>[~]$

此时服务器端输出日志如下:

$./thread_http_server_error.py

query: /hello1 thread=

search041142.sqa.cm4.tbsite.net ? - [15/May/2014 15:02:27] “GET /hello1 HTTP/1.1″ 200 -

success prod query :/hello1

 第2次 curl ,不等待返回,ctrl +C 来模拟客户端断开
[~]$curl -s 'http://10.232.41.142:9001/hello2′

[~]$ ctrl+C

此时服务器端输出日志如下:
query: /hello2 thread=

search041142.sqa.cm4.tbsite.net ? - [15/May/2014 15:33:10] “GET /hello2 HTTP/1.1″ 200 -

socket.error : Connection broke. Aborting[Errno 32] Broken pipe

—————————————-

Exception happened during processing of request from ('10.232.41.142′, 48769)

Traceback (most recent call last):

File “/home/wuzhu/tools/python_2_7_1/lib/python2.7/SocketServer.py”, line 582, in process_request_thread

self.finish_request(request, client_address)

File “/home/wuzhu/tools/python_2_7_1/lib/python2.7/SocketServer.py”, line 323, in finish_request

self.RequestHandlerClass(request, client_address, self)

File “/home/wuzhu/tools/python_2_7_1/lib/python2.7/SocketServer.py”, line 639, in __init__

self.handle()

File “/home/wuzhu/tools/python_2_7_1/lib/python2.7/BaseHTTPServer.py”, line 337, in handle

self.handle_one_request()

File “/home/wuzhu/tools/python_2_7_1/lib/python2.7/BaseHTTPServer.py”, line 326, in handle_one_request

 self.wfile.flush() #actually send the response if not already done.

File “/home/wuzhu/tools/python_2_7_1/lib/python2.7/socket.py”, line 303, in flush

self._sock.sendall(view[write_offset:write_offset+buffer_size])

AttributeError: 'NoneType' object has no attribute 'sendall'

2. 原因分析

“[Errno 32] Broken pipe “ 产生的原因还是比较明确的,由于 client 在服务器返回前主动断开连接,所以服务器在返回时写 socket 收到SIGPIPE报错。虽然在我们的程序中也对异常进行了处理,将handler 的 wfile._sock 对象close 掉 ,但python 的库里BaseHTTPServer.py中BaseHTTPRequestHandler 类的成员函数handle_one_request还是会直接调用 wfile.flush ,而没有判断 wfile 是否已经 close。

def handle_one_request(self):

    """Handle a single HTTP request.

 

    You normally don't need to override this method; see the class

    __doc__ string for information on how to handle specific HTTP

    commands such as GET and POST.

 

    """

    try:

        self.raw_requestline = self.rfile.readline(65537)

        if len(self.raw_requestline) > 65536:

            self.requestline = ''

            self.request_version = ''

            self.command = ''

            self.send_error(414)

            return

        if not self.raw_requestline:

            self.close_connection = 1

            return

        if not self.parse_request():

            # An error code has been sent, just exit

            return

        mname = 'do_' + self.command

        if not hasattr(self, mname):

            self.send_error(501, "Unsupported method (%r)" % self.command)

            return

        method = getattr(self, mname)

        method()

        #没有判断 wfile 是否已经 close 就直接调用 flush()

        self.wfile.flush() #actually send the response if not already done.

    except socket.timeout, e:

        #a read or a write timed out.  Discard this connection

        self.log_error("Request timed out: %r", e)

        self.close_connection = 1

        return

3. 解决办法

只要在RequestHandler重载其基类BaseHTTPRequestHandler的成员函数handle_one_reques(),在调用 wfile.flush() 前加上 wfile 是否已经 close 即可。

#!/usr/bin/env python

#!coding=utf-8
import os

import time

import socket

import threading

from BaseHTTPServer import HTTPServer ,BaseHTTPRequestHandler

from SocketServer import ThreadingMixIn
class RequestHandler(BaseHTTPRequestHandler):

     

    def handle_one_request(self):

        """Handle a single HTTP request.

 

        You normally don't need to override this method; see the class

        __doc__ string for information on how to handle specific HTTP

        commands such as GET and POST.

 

        """

        try:

            self.raw_requestline = self.rfile.readline(65537)

            if len(self.raw_requestline) > 65536:

                self.requestline = ''

                self.request_version = ''

                self.command = ''

                self.send_error(414)

                return

            if not self.raw_requestline:

                self.close_connection = 1

                return

            if not self.parse_request():

                # An error code has been sent, just exit

                return

            mname = 'do_' + self.command

            if not hasattr(self, mname):

                self.send_error(501, "Unsupported method (%r)" % self.command)

                return

            method = getattr(self, mname)

            print "before call do_Get"

            method()

            #增加 debug info 及 wfile 判断是否已经 close

            print "after call do_Get"

            if not self.wfile.closed:

                self.wfile.flush() #actually send the response if not already done.

            print "after wfile.flush()"

        except socket.timeout, e:

            #a read or a write timed out.  Discard this connection

            self.log_error("Request timed out: %r", e)

            self.close_connection = 1

            return

     

    def do_GET(self):

        """

        处理get请求

        """

        query=self.path

        print "query: %s thread=%s" % (query, str(threading.current_thread()))

 

        ret_str="<html>" + self.path + "<br>" + str(self.server) +  "</html>"

 

        time.sleep(5)

         

        try:

            self.send_response(200)

            self.send_header('Content-type','text/html')

            self.end_headers()          

            self.wfile.write(ret_str)

        except socket.error, e:

            print "socket.error : Connection broke. Aborting" + str(e)

            self.wfile._sock.close()

            self.wfile._sock=None

            return False

        

        print "success prod query :%s" % (query)

        return True

 

#多线程处理

class ThreadingHTTPServer(ThreadingMixIn,HTTPServer):

    pass

     

if __name__ == '__main__':

    serveraddr = ('',9001)

 

    ser = ThreadingHTTPServer(serveraddr,RequestHandler)

    ser.serve_forever()

    sys.exit(0)

运行服务
./thread_http_server.py
curl ,不等待返回,ctrl +C 来模拟客户端断开
[~]$curl -s 'http://10.232.41.142:9001/hello2'

[~]$ ctrl+C

此时服务器端输出日志如下:
$./thread_http_server.pybefore call do_Get

query: /hello2 thread=<Thread(Thread-1, started 1103210816)>

search041142.sqa.cm4.tbsite.net - - [15/May/2014 15:54:09] "GET /hello2 HTTP/1.1" 200 -

socket.error : Connection broke. Aborting[Errno 32] Broken pipe

after call do_Get

after wfile.flush()

希望本文所述对大家的Python程序设计有所帮助。
Python 相关文章推荐
django接入新浪微博OAuth的方法
Jun 29 Python
详解使用Python处理文件目录的相关方法
Oct 16 Python
windows下安装Python的XlsxWriter模块方法
May 03 Python
对python中的高效迭代器函数详解
Oct 18 Python
使用Python获取并处理IP的类型及格式方法
Nov 01 Python
详解Python中的测试工具
Jun 09 Python
Python3安装psycopy2以及遇到问题解决方法
Jul 03 Python
Python安装及Pycharm安装使用教程图解
Sep 20 Python
Django实现分页显示效果
Oct 31 Python
pytorch: Parameter 的数据结构实例
Dec 31 Python
python判断一个变量是否已经设置的方法
Aug 13 Python
秀!学妹看见都惊呆的Python小招数!【详细语言特性使用技巧】
Apr 27 Python
python中urllib模块用法实例详解
Nov 19 #Python
python统计一个文本中重复行数的方法
Nov 19 #Python
python通过zlib实现压缩与解压字符串的方法
Nov 19 #Python
python判断字符串是否纯数字的方法
Nov 19 #Python
python使用any判断一个对象是否为空的方法
Nov 19 #Python
python编写暴力破解FTP密码小工具
Nov 19 #Python
用python读写excel的方法
Nov 18 #Python
You might like
PHP 文件上传源码分析(RFC1867)
2009/10/30 PHP
php5.3提示Function ereg() is deprecated Error问题解决方法
2014/11/12 PHP
PHP生成制作验证码的简单实例
2016/06/12 PHP
javascript getElementsByName()的用法说明
2009/07/31 Javascript
js 数组克隆方法 小结
2010/03/20 Javascript
使用jQuery和PHP实现类似360功能开关效果
2014/02/12 Javascript
js获取ajax返回值代码
2014/04/30 Javascript
jQuery 常见小例汇总
2016/12/14 Javascript
详解前端自动化工具gulp自动添加版本号
2016/12/20 Javascript
JavaScript trim 实现去除字符串首尾指定字符的简单方法
2016/12/27 Javascript
JQuery实现定时刷新功能代码
2017/05/09 jQuery
详解如何构建Angular项目目录结构
2017/07/13 Javascript
想用好React的你必须要知道的一些事情
2017/07/24 Javascript
javaScript和jQuery自动加载简单代码实现方法
2017/11/24 jQuery
解决vue 按钮多次点击重复提交数据问题
2018/05/10 Javascript
vue.js删除列表中的一行
2018/06/30 Javascript
详解npm 配置项registry修改为淘宝镜像
2018/09/07 Javascript
在axios中使用params传参的时候传入数组的方法
2018/09/25 Javascript
深入理解react 组件类型及使用场景
2019/03/07 Javascript
vue基础之事件简写、事件对象、冒泡、默认行为、键盘事件实例分析
2019/03/11 Javascript
js笔试题-接收get请求参数
2019/06/15 Javascript
vue3.0生命周期的示例代码
2020/09/24 Javascript
[02:47]DOTA2英雄基础教程 野性怒吼兽王
2013/12/05 DOTA
[05:09]第二届DOTA2亚洲邀请赛决赛日比赛集锦:iG 3:0 OG夺冠
2017/04/05 DOTA
Python实现的朴素贝叶斯算法经典示例【测试可用】
2018/06/13 Python
在Python 不同级目录之间模块的调用方法
2019/01/19 Python
PyQt4实时显示文本内容GUI的示例
2019/06/14 Python
Django实现将一个字典传到前端显示出来
2020/04/03 Python
python Gabor滤波器讲解
2020/10/26 Python
Canvas引入跨域的图片导致toDataURL()报错的问题的解决
2018/09/19 HTML / CSS
荷兰和比利时时尚鞋店:Van Dalen
2018/04/23 全球购物
工程造价专业大学生职业生涯规划书
2014/01/18 职场文书
应届大学生自荐书
2014/06/17 职场文书
2015年结对帮扶工作总结
2015/05/04 职场文书
关于法制教育的宣传语
2015/07/13 职场文书
小学生必读成语故事大全:送给暑假的你们
2019/07/09 职场文书