2013-03-06 3 views
9

यहाँ सर्वर को चलाने के लिए मेरी कोड है:अजगर TCPServer पहले से प्रयोग में है, लेकिन पता मैं सर्वर को बंद करने और मैं का उपयोग `allow_reuse_address`

class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 
    #.... 

PORT = 8089 

httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler) 
httpd.allow_reuse_address = True 

print "Serving forever at port", PORT 
try: 
    httpd.serve_forever() 
except: 
    print "Closing the server." 
    httpd.server_close() 
    raise 

अभी तक तो ऐसा होता है:

^CClosing the server. 
Traceback (most recent call last): 
    File "server.py", line 118, in <module> 
    self.send_error(400, "Unimplemented GET command: %s" % (self.path,)) 
    File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 224, in serve_forever 
    r, w, e = select.select([self], [], [], poll_interval) 
KeyboardInterrupt 
(.virtualenv)[email protected]:~/xxx$ python server.py 
Traceback (most recent call last): 
    File "server.py", line 122, in <module> 
    httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler) 
    File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 402, in __init__ 
    self.server_bind() 
    File "/home/claudiu/local/lib/python2.6/SocketServer.py", line 413, in server_bind 
    self.socket.bind(self.server_address) 
    File "<string>", line 1, in bind 
socket.error: [Errno 98] Address already in use 

क्यों ? मैं सर्वर बंद करता हूं और allow_reuse_address को सत्य पर सेट करता हूं ... पायथन 2.6.8 का उपयोग करना।

उत्तर

13

अन्य उत्तरों के लिए धन्यवाद, मैंने इसे समझ लिया। allow_reuse_address वर्ग पर होना चाहिए, उदाहरण के पर नहीं:

SocketServer.TCPServer.allow_reuse_address = True 
httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler) 

मैं अभी भी क्यों सॉकेट बंद करने इसे सर्वर के अगले रन के लिए, हालांकि मुक्त नहीं किया यकीन नहीं है।

3

ऐसा इसलिए है क्योंकि टीसीपी TIME_WAIT

Somebody discovered this exact problem.

However, if I try to stop and start the server again to test any modifications, I get a random “socket.error: [Errno 98] Address already in use” error. This happens only if a client has already connected to the server.

Checking with netstat and ps, I found that although the process it self is no longer running, the socket is still listening on the port with status “TIME_WAIT”. Basically the OS waits for a while to make sure this connection has no remaining packets on the way.

+0

नहीं एक महान प्रशस्ति पत्र। * पोर्ट * अभी भी * वर्तमान * TIME_WAIT स्थिति में है। कोई सॉकेट नहीं है, और कोई भी नहीं सुन रहा है। – EJP

+0

मैं समझता हूं, लेकिन मैं जानना चाहता था कि मेरे समाधान क्यों (सेट 'allow_reuse_address' सेट करें और शटडाउन पर सॉकेट बंद करें) इसे ठीक नहीं किया। – Claudiu

0

यह है क्योंकि आप SO_REUSEADDRESS इससे पहले कि आप सॉकेट बाँध स्थापित करने के लिए है। जैसे ही आप सॉकेट को एक चरण में बनाते और बाध्य करते हैं और फिर इसे सेट करते हैं, यह पहले से ही बहुत देर हो चुकी है।

+0

आह इसलिए 'allow_reuse_address' मूल रूप से डिफ़ॉल्ट' टीसीपीएस सर्वर 'कार्यान्वयन के लिए कुछ भी नहीं करता है? कार्यक्रम के अंत में सॉकेट को बंद नहीं करना चाहिए इस त्रुटि को रोकें? – Claudiu

3

[Err 98] Address already in use तथ्य सॉकेट .close() था की वजह से है लेकिन यह अभी भी यकीन है कि दूरदराज के टीसीपी कनेक्शन समाप्ति अनुरोध की पावती प्राप्त होने के लिए (TIME_WAIT देखें) पारित करने के लिए पर्याप्त समय के लिए इंतजार कर रहा है। डिफ़ॉल्ट रूप से आप एक सॉकेट बाध्य करने के लिए अगर वहाँ एक सॉकेट कि बंदरगाह के लिए बाध्य की अनुमति नहीं है, लेकिन आप allow_reuse_address (SO_REUSEADDR) के साथ कि ओवरराइड कर सकते हैं

हालांकि TCPServer.allow_reuse_addr उत्परिवर्तित करने के लिए (this other answer में प्रस्तावित) संभव है, मुझे लगता है कि और अधिक साफ है

import SocketServer 
import SimpleHTTPServer 
import time 

class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): 
    def do_GET(): 
     time.sleep(60) 
     self.request.sendall("I'm here!") 

class ReuseAddrTCPServer(SocketServer.TCPServer): 
    allow_reuse_address = True 

PORT = 8089 

httpd = ReuseAddrTCPServer(("", PORT), MyRequestHandler) 
httpd.daemon_threads = True 


print "Serving forever at port", PORT 
try: 
    httpd.serve_forever() 
except: 
    print "Closing the server." 
    httpd.server_close() 
    raise 

आप निश्चित रूप से (वर्गों के साथ खिलवाड़ के बिना) उदाहरण पर ही allow_reuse_address सेट का उपयोग कर सकते हैं, लेकिन आप TCPServer(..., bind_and_activate=False) उपयोग करने की आवश्यकता है, अन्यथा सॉकेट से पहले बाध्य होंगे: TCPServer की अपनी खुद की उपवर्ग जहां allow_reuse_addressTrue के लिए निर्धारित है आपके पास एक मौका है allow_reuse_address सेटिंग बदलें। तो आप मैन्युअल रूप से serve_forever() से पहले .server_bind() और .server_activate() कॉल करने की आवश्यकता:

... 
httpd = SocketServer.TCPServer(("", PORT), MyRequestHandler, bind_and_activate=False) 
httpd.allow_reuse_address = True 
httpd.daemon_threads = True 
... 
httpd.server_bind() 
httpd.server_activate() 
httpd.serve_forever() 
संबंधित मुद्दे

 संबंधित मुद्दे