I have a script which sets up a BasicHTTPServer in a thread so that the main script can automatically open a web browser pointing to the server url to download a file. After the file is downloaded, I want to shut down that server but I have no clue how to go about it. This is an example of what I've done currently:
def server():
HandlerClass = SimpleHTTPRequestHandler
ServerClass = BaseHTTPServer.HTTPServer
Protocol = 'HTTP/1.0'
server_address = ('127.0.0.1', 8000)
HandlerClass.protocol_version = Protocol
httpd = ServerClass(server_address, HandlerClass)
httpd.serve_forever()
def download():
t = threading.Thread(name='server', target=server)
t.start()
webbrowser.open('safari-http://127.0.0.1:8000/')
I want to shut down the server after webbrowser.open().
Thank you
I tried the example given here. Can you check if it worked for you.
runFlag = True
def server(server_class=BaseHTTPServer.HTTPServer,
handler_class=BaseHTTPServer.BaseHTTPRequestHandler):
global runFlag
server_address = ('127.0.0.1', 8000)
HandlerClass.protocol_version = Protocol
httpd = ServerClass(server_address, HandlerClass)
while runFlag:
httpd.handle_request()
httpd.shutdown()
def download():
t = threading.Thread(name='server', target=server)
t.start()
webbrowser.open('https:\\www.google.com')
global runFlag
runFlag = False
So after digging deep through many articles I managed to find a kind of messy solution that works for me which closes the server completely. To do it I incorporated code from the following sources:
The Green Place
Corey Goldberg
UI is a module exclusive to the iOS Python IDE Pythonista which basically just creates buttons "start", "stop" and "visit" which bind to their respective _t functions. The ui.in_background decorator just lets the ui remain responsive while things happen in the background.
self.httpd.socket.close() is what really closes the server but it's messy and prints an ugly error to stdout/err so I had no choice but to suppress it by redirecting stdout/err to a dead class so the error is dropped. Standard stdout/err behaviour is restored immediately after. Thank you all for the time and effort you took to help me, I appreciate it greatly.
import console
import BaseHTTPServer
import SocketServer
from SimpleHTTPServer import SimpleHTTPRequestHandler
import sys
import threading
import webbrowser
from time import sleep
import ui
original_stdout = sys.stdout
original_stderr = sys.stderr
class BasicServer(SocketServer.TCPServer):
allow_reuse_address = True
class NullifyOutput():
def write(self, s):
pass
class ServerThread(threading.Thread):
def __init__(self, ip, port):
super(ServerThread, self).__init__()
self.ip = ip
self.port = port
self.HandlerClass = SimpleHTTPRequestHandler
self.Protocol = 'HTTP/1.0'
self.server_address = (self.ip, self.port)
self.HandlerClass.protocol_version = self.Protocol
try:
self.httpd = BasicServer(self.server_address, self.HandlerClass)
except:
self.port += 1
self.server_address = (self.ip, self.port)
self.httpd = BasicServer(self.server_address, self.HandlerClass)
self.stoptheserver = threading.Event()
def run(self):
while not self.stoptheserver.isSet():
self.httpd.handle_request()
def join(self, timeout=None):
self.stoptheserver.set()
self.httpd.socket.close()
super(ServerThread, self).join(timeout)
server = ServerThread('127.0.0.1', 8000)
def start_t(sender):
print server.isAlive()
if not server.isAlive():
server.start()
def visit_t(sender):
webbrowser.open('http://127.0.0.1:' + str(server.port))
#webbrowser.open('safari-http://127.0.0.1' + str(server.port))
# Use the safari- prefix to open in safari. You may need to switch to
# pythonista then back to safari to get the page to load.
#ui.in_background
def stop_t(sender):
sys.stdout, sys.stderr = NullifyOutput(), NullifyOutput()
server.join(3)
sys.stdout, sys.stderr = original_stdout, original_stderr
ui.load_view('SimpleServer').present('sheet')
Here is an example from cryptoassets.core project, status server:
class StatusHTTPServer(threading.Thread):
def __init__(self, ip, port):
threading.Thread.__init__(self)
self.running = False
self.ready = False
self.ip = ip
self.port = port
def run(self):
self.running = True
self.ready = True
self.httpd.serve_forever()
self.running = False
def start(self):
server_address = (self.ip, self.port)
try:
self.httpd = HTTPServer(server_address, StatusGetHandler)
except OSError as e:
raise RuntimeError("Could not start cryptoassets helper service status server at {}:{}".format(self.ip, self.port)) from e
threading.Thread.start(self)
def stop(self):
if self.httpd and self.running:
self.httpd.shutdown()
self.httpd = None
Related
I need to test a device update function. The function opens a socket on a host and sends a block of text.
The update can take up to 120 seconds. It returns a code for success/failure. To allow continued functioning of the program the update is launched in a thread.
I cannot control the response of the device. The simulation needs to be able to hold an open connection for at least 120 seconds.
It does not need to be safe or scalable since it will only be used for an integration test. The simplest solution is preferred. Pure python is best, but a docker is also acceptable.
I wrote this up based on rdas's pointer.
import json
import logging
import socket
import socketserver
import threading
import time
log = logging.getLogger(__name__)
log.setLevel(logging.INFO)
class LongRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
# Echo the back to the client
data = json.loads(self.request.recv(1024).decode())
t = 0
while t < data['delay']:
time.sleep(1)
print(".", end='')
t += 1
if t % 80 == 0:
print("\n")
print("\n")
self.request.send(b"ok")
class Server():
def __init__(self, host='localhost', port=0):
self.host = host
self.port = port
self.ip = None
self.server = None
def run(self):
address = (self.host, self.port) # let the kernel assign port if port=0
self.server = socketserver.TCPServer(address, LongRequestHandler)
self.ip, self.port = self.server.server_address # what port was assigned?
t = threading.Thread(target=self.server.serve_forever)
t.setDaemon(True) # don't hang on exit
t.start()
return True
def send_request(self, data: dict ):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.ip, self.port))
message = json.dumps(data).encode()
s.send(message)
response = s.recv(1024)
s.close()
return response
def __exit__(self):
self.server.shutdown()
self.server.socket.close()
if __name__ == '__main__':
# For simple testing and config example...
server = Server()
server.run()
# Send the data
d = dict(delay=5) # set delay here to desired
out = server.send_request(d)
print('Received: {!r}'.format(out))
I am new to python and wrote a simple httpserver in python. I am trying to shut down the server from the request to the server. How can I achieve this functionality of calling a function of the server from the handler?
class MyHandler(SimpleHTTPRequestHandler):
def do_GET(self):
if self.path == '/shutdown':
pass # I want to call MainServer.shutdown from here
class MainServer()
def __init__(self, port = 8123):
self._server = HTTPServer(('0.0.0.0', port), MyHandler)
self._thread = threading.Thread(target = self._server.serve_forever)
self._thread.deamon = True
def start(self):
self._thread.start()
def shut_down(self):
self._thread.close()
In short, do not use server.serve_forver(..). The request handler has a self.server attribute that you can use to communicate with the main server instance to set some sort of flag that tell the server when to stop.
import threading
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
class MyHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/shutdown':
self.server.running = False
class MainServer:
def __init__(self, port = 8123):
self._server = HTTPServer(('0.0.0.0', port), MyHandler)
self._thread = threading.Thread(target=self.run)
self._thread.deamon = True
def run(self):
self._server.running = True
while self._server.running:
self._server.handle_request()
def start(self):
self._thread.start()
def shut_down(self):
self._thread.close()
m = MainServer()
m.start()
The server is normally accessible from the handler through the server attribute. A HTTPServer that was started with server_forerver can be shut down with its... shutdown() method. Unfortunately, even if it is not documented, you cannot call shutdown from the thread that runs the server loop because it causes a deadlock. So you could write this in your do_GET handler method:
def do_GET(self):
# send something to requester...
if self.path == '/shutdown':
t = threading.Thread(target = self.server.shutdown)
t.daemon = True
t.start()
This will cleanly let the thread to terminate, and you should also use it as you server shut_down method, because Python threads cannot be closed abruptly:
def shut_down(self):
self._server.shutdown()
I have a problem concerning threading in python (2.7.8). The problem resides in a python "chat" code written (I'll include the code to my threading class and my client class (different python files), since I think the problem is in one of those two, and not in the server code). When I run the Client.py file, I am able to communicate with another client (running the same python code) through a server, but the problem is that I have to refresh the .send_payload(msg) command in order to receive the message that the other client has sent (or simply by pressing enter in the chat, and hence sending "" as message). I want to know if it is possible to receive messages without "refreshing" the chat, somehow through threading.
class MessageReceiver(Thread):
def __init(self,client,connection):
Thread.__init__(self)
self.daemon = True
self.client = client
self.connection = connection
self.stop = False
def run(self):
while not self.stop:
data = self.connection.recv(8192)
if not data:
break
else:
self.client.receive_message(data)
pass
class Client:
def __init__(self, host, server_port):
self.host = host
self.server_port = server_port
self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.run()
def run(self):
self.connection.connect((self.host, self.server_port))
self.thread = MessageReceiver(self, self.connection)
self.thread.start()
while True:
text = raw_input()
if(text.find("login") == 0):
data={"request":"login","content":text[text.find("login")+6:]}
self.send_payload(data)
if(text.find("names") == 0):
data={"request":"names","content":""}
self.send_payload(data)
else:
data={"request":"msg","content":text}
self.send_payload(data)
def disconnect(self):
self.thread.stop = True
self.connection.close()
print("Disconnected")
def receive_message(self, message):
print("Msg: " + message)
def send_payload(self, data):
self.connection.send(json.dumps(data))
print("Payload sent!")
import SocketServer
import sys
from Queue import *
import threading
class CustomTCPServer(SocketServer.TCPServer):
def __init__(self, server_address, RequestHandlerClass, commandQueue=Queue):
self.queue = commandQueue
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate=False)
SocketServer.TCPServer.allow_reuse_address = True
self.server_bind()
self.server_activate()
class SingleTCPHandler(SocketServer.BaseRequestHandler):
def handle(self):
commandQueue = self.server.queue
self.data = self.request.recv(1024).strip()
try:
commandQueue.put(self.data)
except Queue.Empty:
print 'Sorry.. Cannot accept any more.. Queue is full..'
def main():
HOST = ''
PORT = 50099
commandQueue = Queue()
server = CustomTCPServer((HOST, PORT), SingleTCPHandler, commandQueue)
threadObject = threading.Thread(target=server.serve_forever)
threadObject.setDaemon(True)
threadObject.start()
threadObject.join()
if __name__ == '__main__':
main()
But whenever I run the code for second time I get the message that
socket.error: [Errno 98] Address already in use
I am confused..
Any suggestion would be appreciated..
Instead of:
SocketServer.TCPServer.allow_reuse_address = True
Which sets the value on the base class that you've already subclassed yourself from, (and created an instance of),
Use:
self.allow_reuse_address = True
It doesn't look like you're ever closing the socket at the end. Try adding a server.shutdown() (as well as changing the allow_reuse_address) to shut it down at the end after the thread join.
I'm trying to send a message (a string) to a server (say server A) as a response to a particular string message received from the server. I've used a client connection to send messages to the server. I've created my own server (say server B) using socket module to receive the messages from the the above mentioned server. If a certain message is received, to client should send a message to that server A. I used threads so that both my client and server can work concurrently.
Here's my client script (socket1.py).
import socket
import time
s = socket.socket()
s2 = socket.socket()
class MyClient():
def __init__(self):
self.s=socket.socket()
def start(self):
self.s.connect(('localhost',6000))
self.s.settimeout(1000)
self.s.send('JOIN#')
while True:
if self.s.gettimeout():
break
def move(self):
self.s.send('LEFT#')
def close(self):
self.s.close()
def socStart():
global s,s2
s.connect(('localhost',6000))
#s2.connect(('localhost',6000))
s.send('JOIN#')
#time.sleep(10)
#s.send('DOWN#')
#s.close()
def move():
global s1
s1.send('DOWN#')
def close():
global s,s2
s.close()
#s2.close()
Here's my server script (server1.py)
import socket
class MyServer():
def __init__(self):
self.s= socket.socket()
def serStart(self):
self.s.bind(('localhost',7000))
#self.s.settimeout(30)
self.s.listen(5)
self.started = False
while True:
self.c, self.addr = self.s.accept()
self.msg = self.c.recv(1024)
if self.msg[0] == 'S':
self.started = True
print self.addr, '>>', self.msg
self.c.close()
if self.s.gettimeout():
break
self.s.close()
def getStarted(self):
return self.started
Here's the script in which I used threads with both socket1 & server1 module.
import threading
import datetime
import socket1
import server1
import time
class ThreadClass(threading.Thread):
def initialize(self,client,server):
self.client = client
self.server = server
def run(self):
self.client.start()
if self.server.getStarted():
self.client.move()
self.client.close()
class ThreadServer(threading.Thread):
def initialize(self, client, server):
self.client = client
self.server = server
def run(self):
self.server.serStart()
client = socket1.MyClient()
server = server1.MyServer()
t = ThreadClass()
tS=ThreadServer()
t.initialize(client, server)
tS.initialize(client, server)
t.start()
tS.start()
Though server class changes it's started varialble to True the move method doesn't work in ThreadClass. How do I perform such event triggering and responding accordingly with a outside server in python?