#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
sys.dont_write_bytecode = True
import shlex
import subprocess
import SocketServer
sess = []
class TCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
global sess
sess.append(self.request)
ip,port = self.client_address
print "#%d: client %s:%d"%(len(sess),ip,port)
while True:
cmd = self.request.recv(8192)
out = subprocess.check_output(shlex.split(cmd),stderr=subprocess.STDOUT,shell=True)
self.request.send(out)
self.request.close()
class ThreadedTCPServer(SocketServer.ThreadingMixIn,SocketServer.TCPServer): pass
if __name__ == "__main__":
port = 4242
svr = ThreadedTCPServer(("",port),TCPHandler)
print ":%d"%port
svr.serve_forever()
It is much more simple than you think:
class ThreadedTCPServer(SocketServer.ThreadingMixIn,SocketServer.TCPServer): pass
Than you just have to use your new ThreadedTCPServer instead of TCPServer.
For more information you can read some doc.
However in your code you made some mistakes:
The target argument must be a callable object not an "already-called" object.
To handle many requests you need to build a Threads pool. If you only use one thread it does not make any difference if it is the main thread or a "child" thread.
#!/usr/bin/env python
#-*- coding: utf-8 -*-
import sys
sys.dont_write_bytecode = True
import shlex
import subprocess
import SocketServer
sess = []
class TCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
global sess
sess.append(self.request)
ip,port = self.client_address
print "#%d: client %s:%d"%(len(sess),ip,port)
while True:
cmd = self.request.recv(8192)
out = subprocess.check_output(shlex.split(cmd),stderr=subprocess.STDOUT,shell=True)
self.request.send(out)
self.request.close()
class ThreadedTCPServer(SocketServer.ThreadingMixIn,SocketServer.TCPServer): pass
if __name__ == "__main__":
port = 4242
svr = ThreadedTCPServer(("",port),TCPHandler)
print ":%d"%port
svr.serve_forever()
Shouldn't you loop the
server = SocketServer.TCPServer(('',1520), service)
t = Thread(target=server.serve_forever())
t.start()
Just a guess..
Related
I am trying to upgrade my python webserver project to a new QT version (qt4.8 => qt5.x), but the webserver (tornado/flask) is not delivering the website any more. And i don't really know how to debug it.
My main setup is:
Python running on Debian 10 client in VirtualBox (before: Debian 8)
Python3.5 (could be upgraded if necessary)
PySide2 (QT5.x) (before: PySide - QT4.8)
Tornado4.2 (i am willing to upgrade, but the newer versions changed the way the event
loop works and i couldn't get it to work in the past)
Flask
My problem / What i tried
The webbrowser doesn't receive the website (screen is blanc), but also doesn't time out. This can go on for minutes
sudo ss -ltp:
LISTEN 0 128 127.0.0.1:5000 0.0.0.0:* users:(("python3",pid=2037,fd=96))
Code structure
The tornado/flask part is running in a single QThread()
The "main task" runs some general code every 2seconds
main.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PySide2.QtCore import QCoreApplication, QTimer
from T_CTRL import T_CTRL
def main():
# create application
app = QCoreApplication(sys.argv)
app.aboutToQuit.connect(app.deleteLater)
app.processEvents()
# create object for general code
ctrl = T_CTRL()
# create my simple timer task
timerT = QTimer()
timerT.start(2000)
timerT.timeout.connect( ctrl.myTimeTask )
# run application and create main event handler
return app.exec_()
if __name__ == '__main__':
main()
T_CTRL.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PySide2 import QtCore
from PySide2.QtCore import QThread, QCoreApplication
from T_Clean_Exit import T_Clean_Exit
from T_Web_Worker import ThreadWorker
class T_CTRL(QtCore.QObject):
def __init__(self):
print ("init T_CTRL")
# create thread objects for the webserver
self.t = QThread()
self.worker = ThreadWorker()
# configure the main application to handle quit signals correctly
self.cleanExit = T_Clean_Exit(self.t)
# create thread for the webserver
self.worker.moveToThread(self.t)
# connect signals/slots to start the webserver
self.t.started.connect(self.worker.startServer)
# connect signals/slots for the shutdown of thread and webserver
self.worker.sigServerShutdownFinished.connect(self.t.quit)
self.worker.sigServerShutdownFinished.connect(self.worker.deleteLater)
self.cleanExit.sigShutdown.connect(self.t.quit)
self.cleanExit.sigShutdown.connect(self.worker.deleteLater)
self.t.finished.connect(self.t.deleteLater)
# start the webserver thread
self.t.start()
# connect signals/slots for the shutdown of the webserver
self.cleanExit.sigShutdown.connect(self.worker.requestServerStop)
# -------------------------------------------------------------------------
# Timer Task
# -------------------------------------------------------------------------
def myTimeTask(self):
print ("Slow main task...")
# allow other events to be run
QCoreApplication.processEvents()
T_Web_Worker.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PySide2 import QtCore
from flask import Flask, render_template
from tornado.wsgi import WSGIContainer
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
import time
class ThreadWorker(QtCore.QObject):
# init flask & tornado
app = Flask(__name__)
http_server = None
# stuff for server shutdown
MAX_WAIT_SECONDS_BEFORE_SHUTDOWN = 2
sigServerShutdownFinished = QtCore.Signal()
# -------------------------------------------------------------------------
# constructor()
# -------------------------------------------------------------------------
def __init__(self): #, log):
super(ThreadWorker, self).__init__()
# -------------------------------------------------------------------------
# Start the web server
# -------------------------------------------------------------------------
def startServer(self):
self.http_server = HTTPServer(WSGIContainer(self.app))
self.http_server.listen(5000, "127.0.0.1")
IOLoop.instance().start()
# -------------------------------------------------------------------------
# Route: "/"
# -------------------------------------------------------------------------
#app.route('/')
def index():
return render_template('index.html')
# -------------------------------------------------------------------------
# Route: "/*.html"
# -------------------------------------------------------------------------
#app.route('/<path>.html')
def static_html_file(path):
return render_template(path + ".html")
# -------------------------------------------------------------------------
# Request a shutdown of the webserver.
# -------------------------------------------------------------------------
#QtCore.Slot()
def requestServerStop(self):
IOLoop.instance().add_callback(self.shutdownServer)
# -------------------------------------------------------------------------
# Stop the web server
# Don't call this function directly. Always use "requestServerStop()"
# -------------------------------------------------------------------------
def shutdownServer(self):
self.http_server.stop()
io_loop = IOLoop.instance()
deadline = time.time() + self.MAX_WAIT_SECONDS_BEFORE_SHUTDOWN
def stop_loop():
now = time.time()
if now < deadline and (io_loop._callbacks or io_loop._timeouts):
io_loop.add_timeout(now + 1, stop_loop)
else:
io_loop.stop()
stop_loop()
# server has been stopped, now stop the thread
self.sigServerShutdownFinished.emit()
T_Clean_Exit.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
from PySide2 import QtCore
from PySide2.QtCore import QCoreApplication
import signal
from functools import partial
# -------------------------------------------------------------------------
# Properly shutdown the qpplication
# -------------------------------------------------------------------------
class T_Clean_Exit(QtCore.QObject):
sigShutdown = QtCore.Signal()
def __init__(self, objThread):
# init
super(T_Clean_Exit, self).__init__()
self.objThread = objThread # save instance object of thread
# connect quit signals to sigint_handler
signal.signal(signal.SIGINT, partial(self.sigint_handler, str1=""))
signal.signal(signal.SIGTERM, partial(self.sigint_handler, str1=""))
#signal.signal(signal.SIGBREAK, sigint_handler)
def sigint_handler(self, signal, frame, str1):
#Handler for the SIGINT signal
# send Shtudownsignals -> 1) server shutdown 2) thread shutdown
self.sigShutdown.emit()
QCoreApplication.processEvents()
# waiting for the server and thread to shutdown
ret = self.objThread.wait(5000) # wait for thread to close, but max 5000ms
QCoreApplication.processEvents()
# everything has been shut down, now quit the applicaiton
QCoreApplication.quit()
It would be really great if you could give me some guidance.
I have programmed two servers that essentiall do the same with different methods. Both are webservers with a non-blocking ssl wrapper around the socket object. Threads allow multiple requests to be served at the same time.
One uses ThreadingTCPServer and the other calls ThreadingMixIn on the HTTPServer module.
Which one should I use and why if any of them is better than the other?
ThreadingMixIn on the HTTPServer:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, ssl
from socketserver import ThreadingMixIn
from http.server import SimpleHTTPRequestHandler, HTTPServer
MYSERV_WORKDIR = "/media/kingdian/server_pub"
#MYSERV_CLIENTCRT = "/home/ran/keys/client.pem"
MYSERV_FULLCHAIN = "/home/ran/.acme.sh/example.com_ecc/fullchain.cer"
MYSERV_PRIVKEY = "/home/ran/.acme.sh/example.com_ecc/example.com.key"
global sslcontext
sslcontext = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
sslcontext.options |= ssl.OP_NO_TLSv1
sslcontext.options |= ssl.OP_NO_TLSv1_1
#sslcontext.options |= ssl.OP_NO_TLSv1_2
#sslcontext.protocol = ssl.PROTOCOL_TLS
#sslcontext.verify_mode = ssl.CERT_REQUIRED
sslcontext.set_ciphers("ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305")
sslcontext.set_ecdh_curve("secp384r1")
#sslcontext.load_verify_locations(MYSERV_CLIENTCRT)
sslcontext.load_cert_chain(MYSERV_FULLCHAIN, MYSERV_PRIVKEY)
class HSTSHandler(SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
self.send_header("Content-Security-Policy", "default-src 'self'")
self.send_header("X-Content-Type-Options", "nosniff")
self.send_header("X-Frame-Options", "SAMEORIGIN")
self.send_header("X-XSS-Protection", "1; mode=block")
self.send_header("Referrer-Policy", "no-referrer")
SimpleHTTPRequestHandler.end_headers(self)
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
def main():
try:
os.chdir(MYSERV_WORKDIR)#auto-change working directory
SimpleHTTPRequestHandler.sys_version = "002"#display custom Python system version
SimpleHTTPRequestHandler.server_version = "001"#display custom server software version
my_server = ThreadedHTTPServer(('', 443), HSTSHandler)
my_server.socket = sslcontext.wrap_socket(my_server.socket, do_handshake_on_connect=False, server_side=True)
print('Starting server, use <Ctrl-C> to stop')
my_server.serve_forever()
except KeyboardInterrupt:
print(' received, shutting down server')
my_server.shutdown()
if __name__ == '__main__':
main()
ThreadingTCPServer:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, ssl, socketserver
from http.server import SimpleHTTPRequestHandler
MYSERV_WORKDIR = "/media/kingdian/server_pub"
#MYSERV_CLIENTCRT = "/home/ran/keys/client.pem"
MYSERV_FULLCHAIN = "/home/ran/.acme.sh/example.com_ecc/fullchain.cer"
MYSERV_PRIVKEY = "/home/ran/.acme.sh/example.com_ecc/example.com.key"
global sslcontext
sslcontext = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
sslcontext.options |= ssl.OP_NO_TLSv1
sslcontext.options |= ssl.OP_NO_TLSv1_1
#sslcontext.options |= ssl.OP_NO_TLSv1_2
#sslcontext.protocol = ssl.PROTOCOL_TLS
#sslcontext.verify_mode = ssl.CERT_REQUIRED
sslcontext.set_ciphers("ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305")
sslcontext.set_ecdh_curve("secp384r1")
#sslcontext.load_verify_locations(MYSERV_CLIENTCRT)
sslcontext.load_cert_chain(MYSERV_FULLCHAIN, MYSERV_PRIVKEY)
class HSTSHandler(SimpleHTTPRequestHandler):
def end_headers(self):
self.send_header("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
self.send_header("Content-Security-Policy", "default-src 'self'")
self.send_header("X-Content-Type-Options", "nosniff")
self.send_header("X-Frame-Options", "SAMEORIGIN")
self.send_header("X-XSS-Protection", "1; mode=block")
self.send_header("Referrer-Policy", "no-referrer")
SimpleHTTPRequestHandler.end_headers(self)
def main():
try:
os.chdir(MYSERV_WORKDIR)#auto-change working directory
SimpleHTTPRequestHandler.sys_version = "002"#display custom Python system version
SimpleHTTPRequestHandler.server_version = "001"#display custom server software version
my_server = socketserver.ThreadingTCPServer(('', 443), HSTSHandler)
my_server.socket = sslcontext.wrap_socket(my_server.socket, do_handshake_on_connect=False, server_side=True)
print('Starting server, use <Ctrl-C> to stop')
my_server.serve_forever()
except KeyboardInterrupt:
print(' received, shutting down server')
my_server.shutdown()
if __name__ == '__main__':
main()
Those are pretty much two different ways to get to the same end result. If you look at the implementation of ThreadingTCPServer, it's just:
class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass
In the other example, HTTPServer is just a very small wrapper around TCPServer (adds an override in server_bind to store the server hostname and automatically sets allow_reuse_address) and then your code is directly adding the ThreadingMixIn.
So, ultimately, you're going through the same basic code either way. The class hierarchy in the python library has changed slightly over time and so different code examples have ended up doing things in different combinations.
Personally, for your examples, I find the version that uses ThreadingTCPServer cleaner, just because one extra class is handled elsewhere and the code is slightly smaller therefore. OTOH, the other version allows slightly more flexibility since you've already defined a point at which you can control attributes of the threading mix-in, plus you get the additional HTTPServer wrapper bits if that should become important to you.
The code only stops when a keyboardinterrupt is used.
A break was used though I took it out and the adc data was read and then the spi.close was skipped along with the update_sheet("PCEM SHT.1", ADCDATA)
I've tried using a different exception, raise exception based on the number of variables in ADCDATA, but with no effect
# import many libraries
#!/usr/bin/python
# -*- coding: utf-8 -*-
from __future__ import print_function
from googleapiclient.discovery import build
from httplib2 import Http
from oauth2client import file, client, tools
from oauth2client.service_account import ServiceAccountCredentials
import datetime
import spidev # import the SPI driver
def read_mcp3002(channel):
### Working ADC Code
return adc_data
def update_sheet(sheetname, my_list):
###Working Update google sheet code
try:
while True:
Result=1##3.23#for 3302 [mV]..... Voltage=(High Voltage-Low Voltage)/(2^(# of conversion bits))
voltage1=(read_mcp3002(0))
voltage1k=voltage1*Result
voltage2=(read_mcp3002(1))
voltage2k=voltage2*Result # This one #
ADCDATA += [[voltage1k, voltage2k]]
if len(ADCDATA) == 100000:
#print(ADCDATA)
ADCDATA = []
print("+10000")
except KeyboardInterrupt: # Ctrl-C
spi.close()
def main():
update_sheet("PCEM SHT.1", ADCDATA)
if __name__ == '__main__':
main()
The desired result would be to automatically stop at len(ADCDATA)=100000: if len(ADCDATA)==100000, it would run the code in the If statement, and also execute spi.close() and lastly run through def main()'s update_sheet("PCEM SHT1", ADCDATA).
I was able to deal with my problem by importing sys and placing a system exit(1) at the bottom of the & inside the if len(ADCDATA)==100000
if len(ADCDATA)==100000
print("PCEM DATA")
spi.close()
update_sheet"........")
sys.exit(1)
I would like to learn how to call a function asynchronously in Python3. I think Tornado can do this. Currently, my code is returning nothing on the command line:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
async def count(end):
"""Print message when start equals end."""
start = 0
while True:
if start == end:
print('start = {0}, end = {1}'.format(start, end))
break
start = start + 1
def main():
# Start counting.
yield count(1000000000)
# This should print while count is running.
print('Count is running. Async!')
if __name__ == '__main__':
main()
Thanks
To call an async function, you need to provide an event loop to handle it. If you have a Tornado app, it provides such a loop, which allows you to make your handlers asynchronous:
from tornado.web import RequestHandler, url
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
async def do_something_asynchronous():
# e.g. call another service, read from database etc
return {'something': 'something'}
class YourAsyncHandler(RequestHandler):
async def get(self):
payload = await do_something_asynchronous()
self.write(payload)
application = web.Application([
url(r'/your_url', YourAsyncHandler, name='your_url')
])
http_server = HTTPServer(application)
http_server.listen(8000, address='0.0.0.0')
IOLoop.instance().start()
Outside of a Tornado app you can get the event loop from any number of providers, including the built-in asyncio library:
import asyncio
event_loop = asyncio.get_event_loop()
try:
event_loop.run_until_complete(do_something_asynchronous())
finally:
event_loop.close()
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.