本文实例讲述了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′ [~]$ 此时服务器端输出日志如下: $./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提示[Errno 32]Broken pipe导致线程crash错误解决方法的内容,更多相关内容请关注PHP中文网(www.php.cn)!

2小時內可以學會Python的基本編程概念和技能。 1.學習變量和數據類型,2.掌握控制流(條件語句和循環),3.理解函數的定義和使用,4.通過簡單示例和代碼片段快速上手Python編程。

Python在web開發、數據科學、機器學習、自動化和腳本編寫等領域有廣泛應用。 1)在web開發中,Django和Flask框架簡化了開發過程。 2)數據科學和機器學習領域,NumPy、Pandas、Scikit-learn和TensorFlow庫提供了強大支持。 3)自動化和腳本編寫方面,Python適用於自動化測試和系統管理等任務。

兩小時內可以學到Python的基礎知識。 1.學習變量和數據類型,2.掌握控制結構如if語句和循環,3.了解函數的定義和使用。這些將幫助你開始編寫簡單的Python程序。

如何在10小時內教計算機小白編程基礎?如果你只有10個小時來教計算機小白一些編程知識,你會選擇教些什麼�...

使用FiddlerEverywhere進行中間人讀取時如何避免被檢測到當你使用FiddlerEverywhere...

Python3.6環境下加載Pickle文件報錯:ModuleNotFoundError:Nomodulenamed...

如何解決jieba分詞在景區評論分析中的問題?當我們在進行景區評論分析時,往往會使用jieba分詞工具來處理文�...

如何使用正則表達式匹配到第一個閉合標籤就停止?在處理HTML或其他標記語言時,常常需要使用正則表達式來�...


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

Atom編輯器mac版下載
最受歡迎的的開源編輯器

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

禪工作室 13.0.1
強大的PHP整合開發環境

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境