2009-07-18 33 views
8

Tôi đã viết một lớp python rất đơn giản chờ kết nối trên ổ cắm. Mục đích là đưa lớp này vào một ứng dụng hiện có và gửi dữ liệu một cách đồng bộ đến khách hàng kết nối.Chặn khối chấp nhận Python - ngăn ứng dụng thoát khỏi

Vấn đề là khi đợi trên socket.accept(), tôi không thể kết thúc ứng dụng của mình bằng cách nhấn ctrl-c. Tôi không thể phát hiện khi lớp học của tôi nằm ngoài phạm vi và thông báo cho đến khi kết thúc.

Lý tưởng nhất là ứng dụng dưới đây nên thoát sau khi time.sleep (4) hết hạn. Như bạn có thể thấy bên dưới, tôi đã thử sử dụng lựa chọn, nhưng điều này cũng ngăn ứng dụng phản hồi lại ctrl-c. Nếu tôi có thể phát hiện rằng biến 'a' đã vượt quá phạm vi trong phương thức chính, tôi có thể đặt cờ thoát (và giảm thời gian chờ trên lựa chọn để làm cho nó đáp ứng).

Bất kỳ ý tưởng nào?

nhờ


import sys 
import socket 
import threading 
import time 
import select 

class Server(threading.Thread): 
    def __init__(self, i_port): 
     threading.Thread.__init__(self) 
     self.quitting = False 
     self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.serversocket.bind((socket.gethostname(), i_port)) 
     self.serversocket.listen(5) 
     self.start() 

    def run(self): 
     # Wait for connection 
     while not self.quitting: 
      rr,rw,err = select.select([self.serversocket],[],[], 20) 
      if rr: 
       (clientsocket, address) = self.serversocket.accept() 
       clientsocket.close() 

def main(): 
    a = Server(6543) 
    time.sleep(4) 

if __name__=='__main__': 
    main() 

Trả lời

9

Thêm self.setDaemon(True) đến __init__ trước self.start().

(Trong Python 2.6 trở lên, ưu tiên là self.daemon = True).

Ý tưởng quan trọng được giải thích here:

Toàn bộ chương trình Python thoát khi không đề phi daemon sống còn lại.

Vì vậy, bạn cần phải tạo "daemon" của những chủ đề không nên giữ toàn bộ quá trình còn sống chỉ bằng cách sống động. Các chủ đề chính luôn luôn là không daemon, bằng cách này.

+0

Cảm ơn vì điều đó, nó đã thực hiện thủ thuật. Tôi đã thử self.daemon = True nhưng điều đó không làm bất cứ điều gì (tôi đang chạy python 2,5 trên Win32). Thay đổi nó thành self.setDaemon (True) đã thực hiện thủ thuật! cảm ơn! –

4

Tôi không khuyên bạn nên sử dụng tính năng setDaemon để tắt bình thường. Nó cẩu thả; thay vì có một đường dẫn tắt máy sạch cho chủ đề, nó chỉ đơn giản là giết chết các chủ đề mà không có cơ hội để dọn dẹp. Rất tốt để thiết lập nó, vì vậy chương trình của bạn không gặp khó khăn nếu luồng chính thoát đột ngột, nhưng nó không phải là một đường tắt tắt bình thường tốt ngoại trừ hacks nhanh.

import sys, os, socket, threading, time, select 

class Server(threading.Thread): 
    def __init__(self, i_port): 
     threading.Thread.__init__(self) 
     self.setDaemon(True) 
     self.quitting = False 
     self.serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.serversocket.bind((socket.gethostname(), i_port)) 
     self.serversocket.listen(5) 
     self.start() 

    def shutdown(self): 
     if self.quitting: 
      return 

     self.quitting = True 
     self.join() 

    def run(self): 
     # Wait for connection 
     while not self.quitting: 
      rr,rw,err = select.select([self.serversocket],[],[], 1) 
      print rr 
      if rr: 
       (clientsocket, address) = self.serversocket.accept() 
       clientsocket.close() 

     print "shutting down" 
     self.serversocket.close() 

def main(): 
    a = Server(6543) 
    try: 
     time.sleep(4) 
    finally: 
     a.shutdown() 

if __name__=='__main__': 
    main() 

Lưu ý rằng điều này sẽ trì hoãn đến một giây sau khi tắt máy(), hoạt động kém. Điều này thường dễ sửa: tạo một đường ống đánh thức() mà bạn có thể viết vào và bao gồm nó trong lựa chọn; nhưng mặc dù điều này là rất cơ bản, tôi không thể tìm thấy bất kỳ cách nào để làm điều này trong Python. (os.pipe() trả về các bộ mô tả tập tin, không phải các đối tượng tập tin mà chúng ta có thể ghi vào.) Tôi không khai thác sâu hơn, vì nó là một câu đố phức tạp.

+0

Bạn có thể bọc một trình đệ trình vào một đối tượng tệp Python với os.fdopen. Nhưng tôi không đồng ý rằng bất cứ điều gì nhiều hơn setDaemon được bảo đảm khi không có dọn dẹp cụ thể cần thiết trong thread - nó chỉ là một biến chứng nhỏ nhưng không thể phân chia. –

+0

Tôi đã thử một cách tiếp cận rất giống với phương pháp này - phương pháp ShutDown của tôi chỉ đơn giản là thiết lập cờ IsQuitting và kết nối với socket đang được đề cập, qua đó bỏ chặn cuộc gọi accept(), cho phép thread thoát. Tuy nhiên nó dựa vào người dùng gọi ShutDown(). Nhờ đề nghị mặc dù. –

+0

Đối với bất cứ điều gì lớn hơn một hack đơn giản, bạn sẽ cần phải có thể tắt một sợi mà không thoát khỏi toàn bộ quá trình. Ngay cả một máy chủ đơn giản muốn đăng nhập "shutdown thành công" sẽ cần phải làm điều này, hoặc nó vẫn sẽ chấp nhận các kết nối sau khi đăng nhập tắt máy. –

Các vấn đề liên quan