SocketServer does not release port on exit - python

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.

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:
during server initialization I set the third parameter of the __init__ function
false: bind_and_activate = False.
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)

Related

Getting different outputs on Gitbash and VScode Terminal

Below is the smallest reproducible example I could come up with. In the main function, first an object of serverUDP class is created and with the use of threading a function run is called which also creates another thread to call another function RecvData. Problem is the main thread is not printing port value until the program is stopped with ctrl + C. Cannot understand why is this happening.
import socket, simpleaudio as sa
import threading, queue
from threading import Thread
import time
class ServerUDP:
def __init__(self):
while 1:
try:
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s.bind(('127.0.0.1', 0))
self.clients = set()
self.recvPackets = queue.Queue()
break
except:
print("Couldn't bind to that port")
def get_ports(self):
return self.s.getsockname()
def RecvData(self, name, delay, run_event):
while run_event.is_set():
time.sleep(delay)
pass
def run(self, name, delay, run_event):
threading.Thread(target=self.RecvData, args = ("bob",d1,run_event)).start() #separate thread for listening to the clients
while run_event.is_set():
time.sleep(delay)
pass
self.s.close()
def close(self):
self.s.close()
if __name__ == "__main__":
roomserver = ServerUDP()
run_event = threading.Event()
run_event.set()
d1 = 1
t = Thread(target= roomserver.run, args = ("bob",d1,run_event))
t.start()
port = roomserver.get_ports()[1]
print("port is", port)
try:
while 1:
time.sleep(.1)
except KeyboardInterrupt:
print("attempting to close threads. Max wait =",d1)
run_event.clear()
t.join()
print("threads successfully closed")
UPD: I'm on windows platform and was using VScode editor for coding and Git Bash terminal to run this program. I just ran this on VScode terminal and magically it was giving the port number. Is this a known issue in Git Bash terminal?
Adding VScode and Git Bash tags to know something about it.

How create a python application with two thread each which has a autobahn application

I have not found any solution for my problem. I need to create a python application with two thread, each of which is connected to a WAMP Router using autobahn library.
Follow I write the code of my experiment:
wampAddress = 'ws://172.17.3.139:8181/ws'
wampRealm = 's4t'
from threading import Thread
from autobahn.twisted.wamp import ApplicationRunner
from autobahn.twisted.wamp import ApplicationSession
from twisted.internet.defer import inlineCallbacks
class AutobahnMRS(ApplicationSession):
#inlineCallbacks
def onJoin(self, details):
print("Sessio attached [Connect to WAMP Router]")
def onMessage(*args):
print args
try:
yield self.subscribe(onMessage, 'test')
print ("Subscribed to topic: test")
except Exception as e:
print("Exception:" +e)
class AutobahnIM(ApplicationSession):
#inlineCallbacks
def onJoin(self, details):
print("Sessio attached [Connect to WAMP Router]")
try:
yield self.publish('test','YOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO')
print ("Subscribed to topic: test")
except Exception as e:
print("Exception:" +e)
class ManageRemoteSystem:
def __init__(self):
self.runner = ApplicationRunner(url= wampAddress, realm = wampRealm)
def start(self):
self.runner.run(AutobahnMRS);
class InternalMessages:
def __init__(self):
self.runner = ApplicationRunner(url= wampAddress, realm = wampRealm)
def start(self):
self.runner.run(AutobahnIM);
#class S4tServer:
if __name__ == '__main__':
server = ManageRemoteSystem()
sendMessage = InternalMessages()
thread1 = Thread(target = server.start())
thread1.start()
thread1.join()
thread2 = Thread(target = sendMessage.start())
thread2.start()
thread2.join()
When I launch this python application only the thread1 is started and later when I kill the application (ctrl-c) the following error messages are shown:
Sessio attached [Connect to WAMP Router]
Subscribed to topic: test
^CTraceback (most recent call last):
File "test_pub.py", line 71, in <module>
p2 = multiprocessing.Process(target = server.start())
File "test_pub.py", line 50, in start
self.runner.run(AutobahnMRS);
File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/wamp.py", line 175, in run
reactor.run()
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1191, in run
self.startRunning(installSignalHandlers=installSignalHandlers)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1171, in startRunning
ReactorBase.startRunning(self)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 683, in startRunning
raise error.ReactorNotRestartable()
twisted.internet.error.ReactorNotRestartable
I need to implement in one application that has its functionalities and also it must has a system for communicate to a WAMP router with autobahn python library.
In other words, I need a solution able to communicate with a WAMP router, but in the same time this application doesn't must be blocked with the autobahn part (I think that the solution is to start two thread, one thread manages some functions and second thread manages the autobahn part).
With the schema that I proposed before, there is another problem, the need to send message, in a specific topic on the WAMP router, from the application part in the 'no autobahn thread', this functionality should be called through with a specific function without blocking the other functionalities.
I hope I have given all the details.
Thanks a lot for any response
--------------------------------EDIT---------------------------------
After some research I have implemented what I need for websocket protocol, the code is the follow:
# ----- twisted ----------
class _WebSocketClientProtocol(WebSocketClientProtocol):
def __init__(self, factory):
self.factory = factory
def onOpen(self):
#log.debug("Client connected")
self.factory.protocol_instance = self
self.factory.base_client._connected_event.set()
class _WebSocketClientFactory(WebSocketClientFactory):
def __init__(self, *args, **kwargs):
WebSocketClientFactory.__init__(self, *args, **kwargs)
self.protocol_instance = None
self.base_client = None
def buildProtocol(self, addr):
return _WebSocketClientProtocol(self)
# ------ end twisted -------
lass BaseWBClient(object):
def __init__(self, websocket_settings):
#self.settings = websocket_settings
# instance to be set by the own factory
self.factory = None
# this event will be triggered on onOpen()
self._connected_event = threading.Event()
# queue to hold not yet dispatched messages
self._send_queue = Queue.Queue()
self._reactor_thread = None
def connect(self):
log.msg("Connecting to host:port")
self.factory = _WebSocketClientFactory(
"ws://host:port",
debug=True)
self.factory.base_client = self
c = connectWS(self.factory)
self._reactor_thread = threading.Thread(target=reactor.run,
args=(False,))
self._reactor_thread.daemon = True
self._reactor_thread.start()
def send_message(self, body):
if not self._check_connection():
return
log.msg("Queing send")
self._send_queue.put(body)
reactor.callFromThread(self._dispatch)
def _check_connection(self):
if not self._connected_event.wait(timeout=10):
log.err("Unable to connect to server")
self.close()
return False
return True
def _dispatch(self):
log.msg("Dispatching")
while True:
try:
body = self._send_queue.get(block=False)
except Queue.Empty:
break
self.factory.protocol_instance.sendMessage(body)
def close(self):
reactor.callFromThread(reactor.stop)
import time
def Ppippo(coda):
while True:
coda.send_message('YOOOOOOOO')
time.sleep(5)
if __name__ == '__main__':
ws_setting = {'host':'', 'port':}
client = BaseWBClient(ws_setting)
t1 = threading.Thread(client.connect())
t11 = threading.Thread(Ppippo(client))
t11.start()
t1.start()
The previous code work fine, but I need to translate this to operate on WAMP protocol insted websocket.
Does anyone know how I solve ?
The bad news is that Autobahn is using the Twisted main loop, so you can't run it in two threads at once.
The good news is that you don't need to run it in two threads to run two things, and two threads would be more complicated anyway.
The API to get started with multiple applications is a bit confusing, because you have two ApplicationRunner objects, and it looks at first glance that the way you run an application in autobahn is to call ApplicationRunner.run.
However, ApplicationRunner is simply a convenience that wraps up the stuff that sets up the application and the stuff that runs the main loop; the real meat of the work happens in WampWebSocketClientFactory.
In order to achieve what you want, you just need to get rid of the threads, and run the main loop yourself, making the ApplicationRunner instances simply set up their applications.
In order to achieve this, you'll need to change the last part of your program to do this:
class ManageRemoteSystem:
def __init__(self):
self.runner = ApplicationRunner(url=wampAddress, realm=wampRealm)
def start(self):
# Pass start_reactor=False to all runner.run() calls
self.runner.run(AutobahnMRS, start_reactor=False)
class InternalMessages:
def __init__(self):
self.runner = ApplicationRunner(url=wampAddress, realm=wampRealm)
def start(self):
# Same as above
self.runner.run(AutobahnIM, start_reactor=False)
if __name__ == '__main__':
server = ManageRemoteSystem()
sendMessage = InternalMessages()
server.start()
sendMessage.start()
from twisted.internet import reactor
reactor.run()

Soaplib connection - msg 's0:FunctionName', not-found

I have problem with solution that was working very good and suddenly it stopped to do so. I wrote server/client scripts and modules to make a SOAP connection type for my application.
Here is my server code :
import os
import rsglobal
import signal
import soaplib
from soaplib.core.service import rpc, DefinitionBase, soap
from soaplib.core.model.primitive import String, Integer
from soaplib.core.server import wsgi
from soaplib.core.model.clazz import Array
try:
import psycopg
except:
import psycopg2 as psycopg
import rssql
LogFile = "serwer_soap.log"
#-##############################################################################
#-- SOAP SERVER CLASS
#-##############################################################################
class AnakondaSOAPServer(DefinitionBase):
#-##############################################################################
#-- SOAP FUNCTIONS
#-##############################################################################
#soap(String,Integer,_returns=Array(String))
def say_hello(self,name,times):
results = []
for i in range(0,times):
results.append('Hello, %s'%name)
return results
#soap(String,String,_returns=String)
def ConnectToBase(self,name,passwd):
global PolSQL
try:
stat = 'OK'
dane=[]
PolSQL=rssql.RSSQL()
if PolSQL.ConnectToSQL(name,passwd,'127.0.0.1',5432,'','databasename')==1:
stat = u'Connection Error'
SQL='SELECT * FROM table1;'
stat,dane,dump,dump=PolSQL.Execute(SQL,3)
except Exception,e:
return u'Connection Error '+str(e)
return stat+' '+str(dane)
#soap(_returns=String)
def GiveData(self):
global PolSQL
try:
stat = 'OK'
dane=[]
SQL='SELECT * FROM table1;'
stat,dane,dump,dump=PolSQL.Execute(SQL,3)
except Exception,e:
return u'Data getting error '+str(e)
return stat+' '+str(dane)
#------------------------------------------
# ADMINISTRATIVE FUNCTIONS
#------------------------------------------
def SetDefaultData(self):
self._oldHupHandler = signal.SIG_DFL
self._oldAlarmHandler = signal.SIG_DFL
self._oldTermHandler = signal.SIG_DFL
self._childProcess = None
self.PolSQL = None
#-------------------------------------------------------------------------------
def _OnSIGALRM(self, sig, frame):
pass
#-------------------------------------------------------------------------------
def _OnSIGHUP(self, sig, frame):
if self._childProcess:
os.kill(self._childProcess, signal.SIGHUP)
else:
pass
#-------------------------------------------------------------------------------
def _OnSIGTERM(self, sig, frame):
pass
#-------------------------------------------------------------------------------
def _exit(self, status):
if self.PolSQL:
self.PolSQL.DisconnectSQL()
if status:
rsglobal.Log(u"SOAP - finishing : "+str(status), 1)
os._exit(status)
#-------------------------------------------------------------------------------
def StartSOAPServer(self, dbspec,HostSOAP,PortSOAP):
import os
self.dbspec = dbspec
childPID = os.fork()
if childPID:
self._childProcess = childPID
return childPID
else:
try:
signal.signal(signal.SIGUSR1, signal.SIG_DFL)
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
if LogFile:
rsglobal.LogFile = LogFile
self._oldHupHandler = signal.signal(signal.SIGHUP, lambda x, y: self._OnSIGHUP(x, y))
self._oldAlarmHandler = signal.signal(signal.SIGALRM, lambda x, y: self._OnSIGALRM(x, y))
self._oldTermHandler = signal.signal(signal.SIGTERM, lambda x, y: self._OnSIGTERM(x, y))
self.PolSQL = SQLConnect(self.dbspec)
# running SOAP server
from wsgiref.simple_server import make_server
ServiceSoap = soaplib.core.Application([AnakondaSOAPServer],'AnakSOAP',name='AnakSOAP')
WSGI = wsgi.Application(ServiceSoap)
Serwer = make_server(HostSOAP, int(PortSOAP), WSGI)
Serwer.serve_forever()
except Exception, exc:
rsglobal.ZapiszDoLogow(u"Server SOAP Error : "+str(exc), 2)
self._exit(1)
#-------------------------------------------------------------------------------
def StopSOAPServer(self):
if self._childProcess:
os.kill(self._childProcess, signal.SIGTERM)
#-##################################################################
#-### - This is main SOAP server object used in other modules
SerwerSOAP = AnakondaSOAPServer()
SerwerSOAP.SetDefaultData()
#-##############################################################################
#-## ADDITIONAL FUNCTIONS
#-##############################################################################
def SQLConnect(dbspec):
# creates connection to database
PolSQL = rssql.RSSQL()
dbuser, dbpass, dbhost, dbport, dbase = dbspec
if PolSQL.PolaczZSQL(dbuser, dbpass, dbhost, dbport, None, Baza=dbase):
return False
else:
return PolSQL
My client code (which just tests server) is like this :
from suds.client import Client
hello_client = Client('http://128.1.2.3:1234/AnakondaSOAPServer?wsdl')
hello_client.options.cache.clear()
result = hello_client.service.ConnectToBase("username", "password")
print 'Result1',result
result = hello_client.service.GiveData()
print 'Result2',result
Earlier in my main application i use function StartSOAPServer with proper parameters and it's waiting for connections. I can see it with netstat on good adress and port.
After running client script i get :
Traceback (most recent call last):
File "./testsoapclient.py", line 8, in <module>
hello_client = Client('http://128.1.2.3:1234/AnakondaSOAPServer?wsdl')
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/client.py", line 112, in __init__
self.wsdl = reader.open(url)
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/reader.py", line 152, in open
d = self.fn(url, self.options)
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/wsdl.py", line 158, in __init__
self.resolve()
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/wsdl.py", line 207, in resolve
c.resolve(self)
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/wsdl.py", line 494, in resolve
raise Exception("msg '%s', not-found" % op.input)
Exception: msg 's0:ConnectToBase', not-found
Earlier i had problem with visibility of functions after creating a SOAP connection. Solution was to clear a cache. Now i can't even create it.
I use python 2.6, and lately my main app was transfered from 2.4 to 2.6. It's the only difference i can think of.
I tried manipulate with soaplib.core.Application definition, but it didn't work.
Please help :)
I managed to overcome the problems and it's working again.
First thing that repairs situation is splitting server into 2 classes - one to create object and run SOAPServer and second - SOAPServer which contains only definitions of functions.
Even after doing this changes i had bad results. I found out, that damaged structure of server definition hides in /tmp/suds directory (and that is why it was working while having damaged code before). Deleting this files allowed to refresh this structure and all scripts started to work again.

python: simple dbus example- os.fork() in service routine?

I am trying to write dbus server where I want to run some external shell program (grep here) to do the job.
when I do:
prompt$ server.py
then:
prompt$ client.py # works fine, ie. runs grep command in child process.
prompt$ client.py # ..., but second invocation produces following error message:
DBusException: org.freedesktop.DBus.Error.ServiceUnknown: The name org.example.ExampleService was not provided by any .service files
I am stuck. Are You able to help me?
here is server.py (client.py thereafter):
import gtk, glib
import os
import dbus
import dbus.service
import dbus.mainloop.glib
import subprocess
messages_queue=list()
grep_pid=0
def queue_msg(message):
global messages_queue
messages_queue.append(message)
return
def dequeue_msg():
global messages_queue,grep_pid
if grep_pid != 0:
try:
pid=os.waitpid(grep_pid,os.P_NOWAIT)
except:
return True
if pid[0] == 0:
return True
grep_pid=0
if len(messages_queue) == 0:
return True
else:
tekst=messages_queue.pop(0)
cmd="grep 'pp'"
print cmd
#works fine, when I do return here
#return True
grep_pid=os.fork()
if grep_pid != 0:
return True
os.setpgid(0,0)
pop=subprocess.Popen(cmd,shell=True,stdin=subprocess.PIPE)
pop.stdin.write(tekst)
pop.stdin.close()
pop.wait()
exit(0)
class DemoException(dbus.DBusException):
_dbus_error_name = 'org.example.Exception'
class MyServer(dbus.service.Object):
#dbus.service.method("org.example.ExampleInterface",
in_signature='', out_signature='')
def QueueMsg(self):
queue_msg("ppppp")
#dbus.service.method("org.example.ExampleInterface",
in_signature='', out_signature='')
def Exit(self):
mainloop.quit()
from dbus.mainloop.glib import threads_init
if __name__ == '__main__':
glib.threads_init()
threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
name = dbus.service.BusName("org.example.ExampleService", session_bus)
object = MyServer(session_bus, '/My')
glib.timeout_add_seconds(1, dequeue_msg)
mainloop = glib.MainLoop()
print "Running example service."
mainloop.run()
now client.py:
import sys
from traceback import print_exc
import dbus
def main():
bus = dbus.SessionBus()
try:
remote_object = bus.get_object("org.example.ExampleService",
"/My")
except dbus.DBusException:
print_exc()
sys.exit(1)
iface = dbus.Interface(remote_object, "org.example.ExampleInterface")
iface.QueueMsg()
if sys.argv[1:] == ['--exit-service']:
iface.Exit()
if __name__ == '__main__':
main()
You usually get this error message when you try to access a service that is no longer available. Check if your server is still running.
You can use d-feet to debug your dbus connections.
The error message about the missing .service file means that you need to create a service file in dbus-1/services.
For example:
# /usr/local/share/dbus-1/services/org.example.ExampleService.service
[D-BUS Service]
Name=org.example.ExampleService
Exec=/home/user1401567/service.py
A lot of tutorials don't include this detail (maybe .service files didn't use to be required?) But, at least on Ubuntu 12.04, dbus services can't be connected to without it.

how to deal with Python BaseHTTPServer killed,but the port is still be occupied?

I use python BaseHTTPServer,it can handle do_GET,do_POST methods,in do_POST method,i execute linux shell using os.system,when i kill the python script,but the listening port still occupied,so i can't run the script again, the netstat -antp|grep 80 show that the bash/tail is occupied the port 80
import sys
import os
import traceback
import time
import logging.handlers
import logging
from threading import *
from datetime import datetime
import urllib2
reload(sys)
sys.setdefaultencoding('utf-8')
class WebRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
server_version = 'python httpserver'
sys_version = 'b'
backup_dir = None
def do_HEAD(s):
s.send_response(200)
s.send_header("Content-type", "text/html")
s.end_headers()
def do_GET(self):
if self.path == '/foo':
self.send_response(200)
os.system('nohup tail -f a.log &')
else:
self.send_error(404)
if __name__ == "__main__":
try:
server = BaseHTTPServer.HTTPServer(('',80), WebRequestHandler)
server.serve_forever()
except KeyboardInterrupt:
server.socket.close()
File descriptors are inherited by default by child processes, so the socket listening on port 80 is inherited by the command you have launched using your system() call.
To avoid that, you should set the FD_CLOEXEC flag on the listening socket. This can be done by adding (and using) a specific HTTPServer class.
class WebServer(BaseHTTPServer.HTTPServer):
def __init__(self, *args, **kwargs):
BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
# Set FD_CLOEXEC flag
flags = fcntl.fcntl(self.socket.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.socket.fileno(), fcntl.F_SETFD, flags)
Related :
Process started from system command in C inherits parent fd's

Categories