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 相关文章推荐
Python使用Supervisor来管理进程的方法
May 28 Python
常见的python正则用法实例讲解
Jun 21 Python
Python实现的桶排序算法示例
Nov 29 Python
Pycharm如何打断点的方法步骤
Jun 13 Python
Django中Middleware中的函数详解
Jul 18 Python
keras 特征图可视化实例(中间层)
Jan 24 Python
python同时遍历两个list用法说明
May 02 Python
Tensorflow tf.tile()的用法实例分析
May 22 Python
在Mac中配置Python虚拟环境过程解析
Jun 22 Python
Python pytesseract验证码识别库用法解析
Jun 29 Python
python实现sm2和sm4国密(国家商用密码)算法的示例
Sep 26 Python
Python3 多线程(连接池)操作MySQL插入数据
Jun 09 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 curl基本操作详解
2013/07/23 PHP
PHP exif扩展方法开启详解
2014/07/28 PHP
ThinkPHP实现ajax仿官网搜索功能实例
2014/12/02 PHP
Laravel如何使用Redis共享Session
2018/02/23 PHP
php实现有序数组旋转后寻找最小值方法
2018/09/27 PHP
js函数调用常用方法详解
2012/12/03 Javascript
用javascript判断IE版本号简单实用且向后兼容
2013/09/11 Javascript
javascript设计模式之工厂模式示例讲解
2014/03/04 Javascript
Javascript中的异步编程规范Promises/A详细介绍
2014/06/06 Javascript
JS合并数组的几种方法及优劣比较
2014/09/19 Javascript
Jquery $when done then的用法详解
2016/05/20 Javascript
JavaScript知识点总结(六)之JavaScript判断变量数据类型
2016/05/31 Javascript
一种Javascript解释ajax返回的json的好方法(推荐)
2016/06/02 Javascript
JS 日期与时间戮相互转化的简单实例
2016/06/22 Javascript
Jquery实现跨域异步上传文件总结
2017/02/03 Javascript
Vue SPA单页应用首屏优化实践
2018/06/28 Javascript
微信小程序实现卡片层叠滑动效果
2019/06/21 Javascript
js+canvas实现图片格式webp/png/jpeg在线转换
2020/08/22 Javascript
[00:34]TI7不朽珍藏III——纯金地穴编织者饰品展示
2017/07/15 DOTA
[01:00]一分钟回顾2018DOTA2亚洲邀请赛现场活动
2018/04/07 DOTA
python在命令行下使用google翻译(带语音)
2014/01/16 Python
Python实现的单向循环链表功能示例
2017/11/10 Python
Python中join函数简单代码示例
2018/01/09 Python
python实现两个文件夹的同步
2019/08/29 Python
python构建指数平滑预测模型示例
2019/11/21 Python
CSS3实现多背景展示效果通过CSS3定位多张背景
2014/08/10 HTML / CSS
html5 Canvas画图教程(8)—canvas里画曲线之bezierCurveTo方法
2013/01/09 HTML / CSS
快速创建 HTML5 Canvas 电信网络拓扑图的示例代码
2018/03/21 HTML / CSS
加拿大户外探险购物网站:SAIL
2020/06/27 全球购物
省文明单位申报材料
2014/05/08 职场文书
英文求职信范文
2014/05/23 职场文书
大学第二课堂活动总结
2014/07/08 职场文书
社区工作者个人总结
2015/02/28 职场文书
解决golang结构体tag编译错误的问题
2021/05/02 Golang
MySQL系列之四 SQL语法
2021/07/02 MySQL
MySQL中utf8mb4排序规则示例
2021/08/02 MySQL