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遍历文件夹并删除特定格式文件的示例
Mar 05 Python
python集合类型用法分析
Apr 08 Python
win10环境下python3.5安装步骤图文教程
Feb 03 Python
sublime text 3配置使用python操作方法
Jun 11 Python
使用numpy和PIL进行简单的图像处理方法
Jul 02 Python
Python使用sort和class实现的多级排序功能示例
Aug 15 Python
python使用zip将list转为json的方法
Dec 31 Python
详解Python3定时器任务代码
Sep 23 Python
在PyCharm中实现添加快捷模块
Feb 12 Python
python 实现PIL模块在图片画线写字
May 16 Python
使用Python下载抖音各大V视频的思路详解
Feb 06 Python
Python答题卡识别并给出分数的实现代码
Jun 22 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中的Memcache详解
2014/04/05 PHP
destoon常用的安全设置概述
2014/06/21 PHP
详解php中的implements 使用
2017/06/13 PHP
Swoole源码中如何查询Websocket的连接问题详解
2020/08/30 PHP
js实现带按钮的上下滚动效果
2015/05/12 Javascript
javascript框架设计之浏览器的嗅探和特征侦测
2015/06/23 Javascript
高性能JavaScript循环语句和条件语句
2016/01/20 Javascript
JS中this上下文对象使用方式
2016/10/09 Javascript
discuz表情的JS提取方法分析
2017/03/22 Javascript
vue-router 导航钩子的具体使用方法
2017/08/31 Javascript
Web技术实现移动监测的介绍
2017/09/18 Javascript
详解微信小程序回到顶部的两种方式
2019/05/09 Javascript
Vue实例的对象参数options的几个常用选项详解
2019/11/08 Javascript
JS数组及对象遍历方法代码汇总
2020/06/16 Javascript
vue 子组件修改data或调用操作
2020/08/07 Javascript
vue 调用 RESTful风格接口操作
2020/08/11 Javascript
[52:20]VP vs VG Supermajor小组赛 B组胜者组决赛 BO3 第一场 6.2
2018/06/03 DOTA
python实现查询IP地址所在地
2015/03/29 Python
基于python实现微信模板消息
2015/12/21 Python
Python快速从注释生成文档的方法
2016/12/26 Python
Python实现注册、登录小程序功能
2018/09/21 Python
详解Selenium+PhantomJS+python简单实现爬虫的功能
2019/07/14 Python
利用 Flask 动态展示 Pyecharts 图表数据方法小结
2019/09/04 Python
Python实现银行账户资金交易管理系统
2020/01/03 Python
Python使用sqlite3模块内置数据库
2020/05/07 Python
浅谈keras保存模型中的save()和save_weights()区别
2020/05/21 Python
美国一家主营日韩美妆护肤品的在线商店:iMomoko
2016/09/11 全球购物
摩飞电器俄罗斯官方网站:Morphy Richards俄罗斯
2020/07/30 全球购物
学生自我鉴定模板
2013/12/30 职场文书
2014年教师批评与自我批评思想汇报
2014/09/20 职场文书
2015教师个人德育工作总结
2015/07/22 职场文书
2016大学军训心得体会
2016/01/11 职场文书
go语言求任意类型切片的长度操作
2021/04/26 Golang
详细介绍python类及类的用法
2021/05/31 Python
利用Pycharm连接服务器的全过程记录
2021/07/01 Python
ipad隐藏软件app图标方法
2022/04/19 数码科技