كيفية التعامل مع كسر في الأنابيب (SIGPIPE) في بيثون؟

StackOverflow https://stackoverflow.com/questions/180095

  •  05-07-2019
  •  | 
  •  

سؤال

ولقد كتبت بسيط متعددة الخيوط الخادم لعبة الثعبان في أن يخلق موضوع جديد لكل اتصال العميل. أنا وجدت أن بين الحين والآخر، سيقوم الملقم تحطم بسبب كسر في الأنابيب / خطأ SIGPIPE. وأنا متأكد من أنه يحدث عندما يحاول برنامج لإرسال استجابة إلى عميل التي لم تعد موجودة.

ما هو وسيلة جيدة للتعامل مع هذا؟ قرار بلدي يفضل أن مجرد إغلاق الاتصال من جانب الخادم إلى العميل والمضي قدما، بدلا من الخروج من البرنامج بأكمله.

وPS: هذا السؤال / الجواب يتناول المشكلة بطريقة عامة؛ كيف على وجه التحديد يجب أن حلها؟

هل كانت مفيدة؟

المحلول

وتقرأ على المحاولة: بيان

try:
    # do something
except socket.error, e:
    # A socket error
except IOError, e:
    if e.errno == errno.EPIPE:
        # EPIPE error
    else:
        # Other error

نصائح أخرى

وعلى افتراض أن كنت تستخدم وحدة مأخذ القياسية، يجب أن تكون اصطياد استثناء socket.error: (32, 'Broken pipe') (لا IOError عن غيرهم وقد اقترح). سيتم رفع هذا في حالة أن كنت قد وصفت، أي إرسال / الكتابة إلى مأخذ التي الجانب البعيد قد قطع.

import socket, errno, time

# setup socket to listen for incoming connections
s = socket.socket()
s.bind(('localhost', 1234))
s.listen(1)
remote, address = s.accept()

print "Got connection from: ", address

while 1:
    try:
        remote.send("message to peer\n")
        time.sleep(1)
    except socket.error, e:
        if isinstance(e.args, tuple):
            print "errno is %d" % e[0]
            if e[0] == errno.EPIPE:
               # remote peer disconnected
               print "Detected remote disconnect"
            else:
               # determine and handle different error
               pass
        else:
            print "socket error ", e
        remote.close()
        break
    except IOError, e:
        # Hmmm, Can IOError actually be raised by the socket module?
        print "Got IOError: ", e
        break

لاحظ أن هذا الاستثناء لن تثار دائما على الكتابة الأولى إلى مأخذ مغلقة - أكثر عادة الكتابة الثاني (إلا إذا كان عدد بايت مكتوب في الكتابة الأول أكبر من حجم المخزن المؤقت مأخذ ل). تحتاج أن تضع ذلك في الاعتبار في حال طلبك يعتقد أن النهاية البعيدة إلى البيانات الواردة من الكتابة الأولى عندما قد قطع بالفعل.

ويمكنك الحد من حدوث (ولكن ليس القضاء تماما) من هذه باستخدام select.select() (أو poll). التحقق من وجود بيانات جاهزة للقراءة من الأقران قبل محاولة الكتابة. إذا تقارير select أن هناك بيانات متاحة للقراءة من مأخذ الأقران، وقراءتها باستخدام socket.recv(). إذا كان هذا بإرجاع سلسلة فارغة، النظير البعيد تم إغلاق الاتصال. لأنه ما زال هناك حالة تعارض هنا، فسوف لا تزال بحاجة لالتقاط ومعالجة الاستثناء.

وملتوية تعتبر كبيرة بالنسبة لهذا النوع من الشيء، ومع ذلك، فإنه يبدو وكأنه كنت قد كتبت بالفعل عادلة قليلا من التعليمات البرمجية.

وSIGPIPE (على الرغم من انني اعتقد انك تعني EPIPE؟) ويحدث على مآخذ عند إيقاف مأخذ ثم إرسال البيانات إلى ذلك. الحل بسيط هو عدم اغلاق مأخذ أسفل قبل محاولة إرساله البيانات. يمكن أن يحدث هذا أيضا على أنابيب، ولكن لا يبدو أن هذا ما كنت تعاني، منذ كان خادم الشبكة.

ويمكنك أيضا مجرد تطبيق إسعافات أولية من اصطياد استثناء في بعض معالج المستوى الأعلى في كل موضوع.

وبطبيعة الحال، إذا كنت تستخدم ملتوية بدلا من وضع البيض موضوع جديد لكل اتصال العميل، وربما كنت ولدن ' ر لها هذه المشكلة. انها حقا من الصعب (ربما من المستحيل، اعتمادا على التطبيق الخاص بك) للحصول على ترتيب وثيقة وعمليات الكتابة الصحيحة إذا مواضيع متعددة تتعامل مع نفس القناة I / O.

وأنا وجه مع نفس السؤال. ولكن يمكنني تقديم نفس الرمز في المرة القادمة، وأنها تعمل فقط. وهي المرة الأولى التي كسرت:

$ packet_write_wait: Connection to 10.. port 22: Broken pipe

والمرة الثانية يعمل:

[1]   Done                    nohup python -u add_asc_dec.py > add2.log 2>&1

واعتقد ان السبب قد يكون عن بيئة الخادم الحالية.

وجوابي هو قريب جدا من لS.Lott، إلا أنني سأكون أكثر خاص:

try:
    # do something
except IOError, e:
    # ooops, check the attributes of e to see precisely what happened.
    if e.errno != 23:
        # I don't know how to handle this
        raise

وحيث "23" هو رقم الخطأ الذي تحصل عليه من EPIPE. بهذه الطريقة فلن محاولة للتعامل مع خطأ أذونات أو أي شيء آخر كنت غير مجهزة ل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top