Shutdown for socketserver based Python 3 server hangs

2024/10/18 12:46:23

I am working on a "simple" server using a threaded SocketServer in Python 3.

I am going through a lot of trouble implementing shutdown for this. The code below I found on the internet and shutdown works initially but stops working after sending a few commands from the client via telnet. Some investigation tells me it hangs in threading._shutdown... threading._wait_for_tstate_lock but so far this does not ring a bell.

My research tells me that there are ~42 different solutions, frameworks, etc. on how to do this in different python versions. So far I could not find a working approach for python3. E.g. I love telnetsrv(https://pypi.python.org/pypi/telnetsrv/0.4) for python 2.7 (it uses greenlets from gevent) but this one does not work for python 3. So if there is a more pythonic, std lib approach or something that works reliably I would love to hear about it!

My bet currently is with socketserver but I could not figure out yet how to deal with the hanging server. I removed all the log statements and most functionality so I can post this minimal server which exposes the issue:

# -*- coding: utf-8 -*-
import socketserver
import threadingSERVER = Nonedef shutdown_cmd(request):global SERVERrequest.send(bytes('server shutdown requested\n', 'utf-8'))request.close()SERVER.shutdown()print('after shutdown!!')#SERVER.server_close()class service(socketserver.BaseRequestHandler):def handle(self):while True:try:msg = str(self.request.recv(1024).strip(), 'utf-8')if msg == 'shutdown':shutdown_cmd(msg, self.request)else:self.request.send(bytes("You said '{}'\n".format(msg), "utf-8"))except Exception as e:passclass ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):passdef run():global SERVERSERVER = ThreadedTCPServer(('', 1520), service)server_thread = threading.Thread(target=SERVER.serve_forever)server_thread.daemon = Trueserver_thread.start()input("Press enter to shutdown")SERVER.shutdown()if __name__ == '__main__':run()

It would be great being able to stop the server from the handler, too (see shutdown_cmd)

Answer

shutdown() works as expected, the server has stopped accepting new connections, but python still waiting for alive threads to terminate.

By default, socketserver.ThreadingMixIn will create new threads to handle incoming connection and by default, those are non-daemon threads, so python will wait for all alive non-daemon threads to terminate.

Of course, you could make the server spawn daemon threads, then python will not waiting:

The ThreadingMixIn class defines an attribute daemon_threads, which indicates whether or not the server should wait for thread termination. You should set the flag explicitly if you would like threads to behave autonomously; the default is False, meaning that Python will not exit until all threads created by ThreadingMixIn have exited.

class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):daemon_threads = True

But that is not the ideal solution, you should check why threads never terminate, usually, the server should stop processing connection when no new data available or client shutdown connection:

import socketserver
import threadingshutdown_evt = threading.Event()class service(socketserver.BaseRequestHandler):def handle(self):self.request.setblocking(False)while True:try:msg = self.request.recv(1024)if msg == b'shutdown':shutdown_evt.set()breakelif msg:self.request.send(b'you said: ' + msg)if shutdown_evt.wait(0.1):breakexcept Exception as e:breakclass ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):passdef run():SERVER = ThreadedTCPServer(('127.0.0.1', 10000), service)server_thread = threading.Thread(target=SERVER.serve_forever)server_thread.daemon = Trueserver_thread.start()input("Press enter to shutdown")shutdown_evt.set()SERVER.shutdown()if __name__ == '__main__':run()
https://en.xdnf.cn/q/72954.html

Related Q&A

How do I url encode in Python?

I tried this: but it doesnt work.print urllib.urlencode("http://"+SITE_DOMAIN+"/go/")I want to turn it into a string with url encodings

resampling pandas series with numeric index

suppose I have a pandas.Series with index with numeric value type e.g. pd.Series( [10,20], [1.1, 2.3] )How do we resample above series with 0.1 interval? look like the .resample func only work on date…

Python3 Tkinter popup menu not closing automatically when clicking elsewhere

Im running Python 3.3.3 (and right now Im on Ubuntu but I also develop on Mac and Windows, which I havent yet tested). I have a Treeview object that responds to right click on items and shows a context…

How does python process a signal?

What is the workflow of processing a signal in python ? I set a signal handler, when the signal occur ,how does python invoke my function? Does the OS invoke it just like C program? If I am in a C e…

Pandas Dataframe to dict grouping by column

I have a dataframe like this:Subject_id Subject Score Subject_1 Math 5 Subject_1 Language 4 Subject_1 Music 8 Subject_2 …

How can I use a Perl module from Python?

There exists a Perl module that provides the perfect functionality for my Python app. Is there any way for me to utilize it? (it is complicated, it would take me a month to port it)I dont want to hav…

HTTPS log in with urllib2

I currently have a little script that downloads a webpage and extracts some data Im interested in. Nothing fancy.Currently Im downloading the page like so:import commands command = wget --output-docume…

Filter values inside Python generator expressions

I have a dictionary dct for which I want each of its values to be summed provided their corresponding keys exist in a specified list lst.The code I am using so far is:sum(dct[k] for k in lst)In the abo…

Python and tfidf algorithm, make it faster?

I am implementing the tf-idf algorithm in a web application using Python, however it runs extremely slow. What I basically do is:1) Create 2 dictionaries:First dictionary: key (document id), value (lis…

How to use Python to find all isbn in a text file?

I have a text file text_isbn with loads of ISBN in it. I want to write a script to parse it and write it to a new text file with each ISBN number in a new line.Thus far I could write the regular expres…