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中cPickle用法例子分享
Jan 03 Python
python创建进程fork用法
Jun 04 Python
Python2.X/Python3.X中urllib库区别讲解
Dec 19 Python
PyTorch上搭建简单神经网络实现回归和分类的示例
Apr 28 Python
浅谈pycharm出现卡顿的解决方法
Dec 03 Python
对python requests发送json格式数据的实例详解
Dec 19 Python
python 将字符串完成特定的向右移动方法
Jun 11 Python
django 消息框架 message使用详解
Jul 22 Python
详解有关PyCharm安装库失败的问题的解决方法
Feb 02 Python
解决python 找不到module的问题
Feb 12 Python
python控制台打印log输出重复的解决方法
May 14 Python
Python3 类型标注支持操作
Jun 02 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实现Linux服务器木马排查及加固功能
2014/12/29 PHP
php+ajax无刷新分页实例详解
2015/12/07 PHP
php通过会话控制实现身份验证实例
2016/10/18 PHP
PHP使用PDO抽象层获取查询结果的方法示例
2018/05/10 PHP
PHP设计模式之观察者模式定义与用法示例
2018/08/04 PHP
php实现通过stomp协议连接ActiveMQ操作示例
2020/02/23 PHP
跨浏览器的设置innerHTML方法
2006/09/18 Javascript
jquery遍历checkbox的注意事项说明
2014/02/21 Javascript
JS、CSS以及img对DOMContentLoaded事件的影响
2014/08/12 Javascript
node.js中的fs.writeFile方法使用说明
2014/12/14 Javascript
实例详解JSON数据格式及json格式数据域字符串相互转换
2016/01/07 Javascript
Express与NodeJs创建服务器的两种方法
2017/02/06 NodeJs
jQuery插件FusionCharts实现的2D柱状图效果示例【附demo源码下载】
2017/03/06 Javascript
JS实现的简单拖拽功能示例
2017/03/13 Javascript
基于vue实现多引擎搜索及关键字提示
2017/03/16 Javascript
js时间戳与日期格式之间相互转换
2017/12/11 Javascript
JavaScript中Object基础内部方法图
2018/02/05 Javascript
jQuery基于Ajax实现读取XML数据功能示例
2018/05/31 jQuery
vue绑定事件后获取绑定事件中的this方法
2018/09/15 Javascript
JS+CSS3实现的简易钟表效果示例
2019/04/13 Javascript
解决layui弹出层layer的area过大被遮挡的问题
2019/09/21 Javascript
vue element和nuxt的使用技巧分享
2021/01/14 Vue.js
在Python中操作字典之setdefault()方法的使用
2015/05/21 Python
Python中利用Scipy包的SIFT方法进行图片识别的实例教程
2016/06/03 Python
Python图片转换成矩阵,矩阵数据转换成图片的实例
2018/07/02 Python
vim自动补全插件YouCompleteMe(YCM)安装过程解析
2019/10/21 Python
详解Python中打乱列表顺序random.shuffle()的使用方法
2019/11/11 Python
Python实现ATM系统
2020/02/17 Python
python对XML文件的操作实现代码
2020/03/27 Python
澳大利亚在线消费电子产品商店:TobyDeals
2020/01/05 全球购物
入党积极分子介绍信
2014/01/17 职场文书
科研课题实施方案
2014/03/18 职场文书
教学改革实施方案
2014/03/31 职场文书
上手简单,功能强大的Python爬虫框架——feapder
2021/04/27 Python
vue3使用vuedraggable实现拖拽功能
2022/04/06 Vue.js
《总之就是很可爱》新作短篇动画《总之就是很可爱~制服~》将于2022年夏天播出
2022/04/07 日漫