2

I have the following issue with Python (2.7) socketserver:

import wx
import socket
from SocketServer import BaseRequestHandler, ThreadingTCPServer
from threading import Thread
from wx.lib.pubsub import pub
from GUI import GUI

class LogHandler(BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        wx.CallAfter(pub.sendMessage, 'logmsg', msg=data)
        self.request.close()

class MyTestGUI(GUI):
    def __init__(self):
        super(MyTestGUI, self).__init__(None)
        pub.subscribe(self.AppendLog, 'logmsg')

        self.LogServer = ThreadingTCPServer(('', 10010), LogHandler)
        self.LogServer.allow_reuse_address = True
        self.thd = Thread(target=self.LogServer.serve_forever)
        self.thd.daemon = True
        self.thd.start()

    def AppendLog(self, msg):
        # Append the mesage
        print(msg)

    def AppClose(self, event):
        self.LogServer.shutdown()
        self.LogServer.server_close()
        exit()

if __name__ == '__main__':
    app = wx.App()
    frame = MyTestGUI()
    frame.Show(True)
    app.MainLoop()

This server is supposed to receive messages from a device (which closes the socket upon message sent). On the first run the code works ok, but after restart I get the following exception:

    self.LogServer = ThreadingTCPServer(('', 10010), LogHandler)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 420, in __init__
    self.server_bind()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 434, in server_bind
    self.socket.bind(self.server_address)
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 228, in meth
    return getattr(self._sock,name)(*args)
socket.error: [Errno 48] Address already in use

LogServer.allow_reuse_address = True / False, does not change a thing.

Peter V
  • 71
  • 4

1 Answers1

3

I had the same problem in Python 3.7.2 with a (non-threading) socketserver.TCPServer instance. ( I use anaconda on opensuse, in case it matters )

My solution:

  1. during server initialization I set the third parameter of the __init__ function false: bind_and_activate = False.
  2. After initialization I set the .allow_reuse_address flag to True, and the .server_bind() and .server_activate() funs were called only after this flag setting.

I think that the important thing is to set the bind_and_activate flag before bindig and activating the server, since if the bind_and_activate parameter during TCPServer initialization is True or not set, then the TCPServer.__init__() calls both the server_bind() and server_activate() funtion. And in this case I could not change the value of the .allow_reuse_address flag - I could see it from the print() calls .

(Note that the code below does not work since the request handler definition is missing from it. I also use timeout, but that is independent of the problem )

def set_up_server_for_one_request(host, port, reqHandler, timeout = 600):
    ''' set up a server for one request. there is timeout as well.
    '''
        
    with socketserver.TCPServer((host, port), reqHandler, \
                                bind_and_activate= False) as serverInstance:  
                
        print('reuse  adress attribute before flag setting: ',\
              serverInstance.socket.getsockopt(socket.SOL_SOCKET,\
                                               socket.SO_REUSEADDR))#print flagVal before setting
        
        serverInstance.allow_reuse_address = True
        
        print('reuse  adress attribute after flag setting: ',\
              serverInstance.socket.getsockopt(socket.SOL_SOCKET, \
                                               socket.SO_REUSEADDR)) #print flagVal after setting
        
        print('server adress: ', serverInstance. server_address)
            
        serverInstance.server_bind()
        
        serverInstance.server_activate()
        
        serverInstance.timeout = timeout    #set server's timeout
        
        serverInstance.handle_request()
        
    print('server finished, and exits')
    
            

if __name__ == '__main__':
    
    set_up_server_for_one_request(host = 'localhost', port = 9998,\
                                  reqHandler = My_EchoRH, timeout = 20)