import sys
import socket
import threading
import time
QUIT = False
class ClientThread(threading.Thread): # Class that implements the client threads in this server
def __init__(self, client_sock): # Initialize the object, save the socket that this thread will use.
threading.Thread.__init__(self)
self.client = client_sock
def run(self): # Thread's main loop. Once this function returns, the thread is finished and dies.
global QUIT # Need to declare QUIT as global, since the method can change it/
done = False
cmd = self.readline() #Read data from the socket and process it
while not done:
if 'quit' == cmd:
self.writeline('Ok, bye')
QUIT = True
done = True
elif 'bye' == cmd:
self.writeline('Ok, bye')
done = True
else:
self.writeline(self.name)
cmd = self.readline()
self.client.close() # Make sure socket is closed when we're done with it
return
def readline(self): # Helper function, read up to 1024 chars from the socket, and returns them as a string
result = self.client.recv(1024)
if None != result: # All letters in lower case and without and end of line markers
result = result.strip().lower()
return result
def writeline(self, text): # Helper function, writes the given string to the socket with and end of line marker at end
self.client.send(text.strip() + '\n')
class Server: # Server class. Opens up a socket and listens for incoming connections.
def __init__(self): # Every time a new connection arrives, new thread object is created and
self.sock = None # defers the processing of the connection to it
self.thread_list = []
def run(self): # Server main loop: Creates the server (incoming) socket, listens > creates thread to handle it
all_good = False
try_count = 0 # Attempt to open the socket
while not all_good:
if 3 < try_count: # Tried more than 3 times without success, maybe post is in use by another program
sys.exit(1)
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create the socket
port = 80
self.sock.bind(('127.0.0.1', port)) # Bind to the interface and port we want to listen on
self.sock.listen(5)
all_good = True
break
except socket.error, err:
print('Socket connection error... Waiting 10 seconds to retry.')
del self.sock
time.sleep(10)
try_count += 1
print( 'Server is listening for incoming connections.')
print('Try to connect through the command line with:')
print('telnet localhost 80')
print('and then type whatever you want.')
print()
print("typing 'bye' finishes the thread. but not the server",)
print("eg. you can quit telnet, run it again and get a different ",)
print("thread name")
print("typing 'quit' finishes the server")
try:
while not QUIT:
try:
self.sock.settimeout(0.500)
client = self.sock.accept()[0]
except socket.timeout:
time.sleep(1)
if QUIT:
print('Received quit command. Shutting down...')
break
continue
new_thread = ClientThread(client)
print('Incoming Connection. Started thread ',)
print(new_thread.getName())
self.thread_list.append(new_thread)
new_thread.start()
for thread in self.thread_list:
if not thread.isAlive():
self.thread_list.remove(thread)
thread.join()
except KeyboardInterrupt:
print('Ctrl+C pressed... Shutting Down')
except Exception as err:
print('Exception caught: %s\nClosing...' % err)
for thread in self.thread_list:
thread.join(1.0)
self.sock.close()
if "__main__" == __name__:
server = Server()
server.run()
print('Terminated')
Resolved many issues, these are the ones left, thank you guys!
1st error: socket.error, err.This specifically tells me that this no longer works in Python 3.4, but does not offer an alternative.
2nd Error: except socket.error, err: Python 3.4 does not support this syntax
3rd Error: self.readline(), I also have to assume writeline does not work also.
In this case, self.readline() is totally not working, I get an error that says AttributeError: 'ClientThread' object has no attribute 'readline'
This only happens after the thread is created. Console shows:
Incoming connection. Started thread.
Thread-1
Then flags that error.
4th Error: Cannot get 2to3 to run? Terminal says not recognised as internal command, and python console gives a big FU.
Can I get any rectification suggestions for the following errors please?
There are multiple issues that prevent your code from woring on python3
you're using python2 print statements, so your code can't possibly run on python3 where print() is a function.
the recv and send methods require/return bytes in python3, not str
the syntax for catching errors is except ExceptionClass as name
The first step in porting Python 2 code to Python 3 is to run it though the 2to3 program that comes with Python.
If you run your code through 2to3 with the -w option, it will fix a lot of your problems automagically.
> 2to3 -w --no-diffs socktest1.py
If you want to see what would be changed, but not change anything;
> 2to3 socktest1.py |less
Related
I've created a RPyC server. Connecting works, all my exposed methods work. Now I am looking to shut down the server from the client. Is this even possible? Security is not a concern as I am not worried about a rogue connection shutting down the server.
It is started with (Which is blocking):
from rpyc import ThreadPoolServer
from service import MyService
t = ThreadPoolServer(MyService(), port=56565)
t.start()
Now I just need to shut it down. I haven't found any documentation on stopping the server.
You can add to your Service class the method:
def exposed_stop(self):
pid = os.getpid()
if platform.system() == 'Windows':
PROCESS_TERMINATE = 1
handle = ctypes.windll.kernel32.OpenProcess(PROCESS_TERMINATE, False, pid)
ctypes.windll.kernel32.TerminateProcess(handle, -1)
ctypes.windll.kernel32.CloseHandle(handle)
else:
os.kill(pid, signal.SIGTERM)
This will make the service get its own PID and send SIGTERM to itself. There may be an better way of doing this hiding in some dark corner of the API, but I've found no better method.
If you want to do clean-up before your thread terminates, you can set up exit traps:
t = rpyc.utils.server.ThreadedServer(service, port=port, auto_register=True)
# Set up exit traps for graceful exit.
signal.signal(signal.SIGINT, lambda signum, frame: t.close())
signal.signal(signal.SIGTERM, lambda signum, frame: t.close())
t.start() # blocks thread
# SIGTERM or SIGINT was received and t.close() was called
print('Closing service.')
t = None
shutil.rmtree(tempdir)
# etc.
In case anybody is interested, I have found another way of doing it.
I'm just making the server object on a global scope, and then adding an exposed method to close it.
import rpyc
from rpyc.utils.server import ThreadedServer
class MyService(rpyc.Service):
def exposed_stop(self):
server.close()
def exposed_echo(self, text):
print(text)
server = ThreadedServer(MyService, port = 18812)
if __name__ == "__main__":
print("server start")
server.start()
print("Server closed")
On the client side, you will have an EOF error due to the connection being remotely closed. So it's better to catch it.
import rpyc
c = rpyc.connect("localhost", 18812)
c.root.echo("hello")
try :
c.root.stop()
except EOFError as e:
print("Server was closed")
EDIT: I needed to be able to dinamically specify the server. So I came with this (Is it better ? I don't know, but it works well. Be careful though, if you have multiple server running this service: things could become weird):
import rpyc
from rpyc.utils.server import ThreadedServer
class MyService(rpyc.Service):
_server:ThreadedServer
#staticmethod
def set_server(inst=ThreadedServer):
MyService._server = inst
def exposed_stop(self):
if self._server:
self._server.close()
def exposed_echo(self, text):
print(text)
if __name__ == "__main__":
server = ThreadedServer(MyService, port = 18812)
MyService.set_server(server)
print("server start")
server.start()
print("Server closed")
PS: It probably is possible to avoid the EOF error by using Asynchronous Operations
I am attempting to make use of concurrent.futures.ThreadPoolExecutor for the first time. One of my threads (level_monitor) consistently hangs on a call to datetime.now.strftime()—and on another hardware-specific function. For now I am assuming it is the same fundamental problem in both cases.
I've created a reproducible minimum example.
from concurrent.futures import ThreadPoolExecutor
import socket
from time import sleep
status = 'TRY AGAIN\n'
def get_level():
print('starting get_level()')
while True:
sleep(2)
now = datetime.now().strftime('%d-%b-%Y %H:%M:%S')
print('get_level woken...')
# report status when requested
def serve_level():
print('starting serve_level()')
si = socket.socket()
port = 12345
si.bind(('127.0.0.1',port))
si.listen()
print('socket is listening')
while True:
ci, addr = si.accept()
print('accepted client connection from ',addr)
with ci:
req = ci.recv(1024)
print( req )
str = status.encode('utf-8')
ci.send(str)
ci.close()
if __name__ == '__main__':
nthreads = 5
with ThreadPoolExecutor(nthreads) as executor:
level_monitor = executor.submit(get_level)
server = executor.submit(serve_level)
When I run it I see the serve_level thread works fine. I can talk to that thread using telnet. I can see the level_monitor thread starts too, but then it hangs before print('get_level woken...'). If I comment out the call to datetime then the thread behaves as expected.
I am sure that when I find out why I will have found out a lot.
This is the server.py file which runs a basic server:
import socket
import sys
sockett = socket.socket()
sockett.bind(('127.0.0.1', 123))
sockett.listen(10)
while True:
print('1', end='')
while True:
print('2', end='')
try:
client, addr = sockett.accept()
print(client,addr)
break
except Exception as e:
print(e)
print(client.recv(400))
print(client.recv(1024))
print('3')
print('4')
And this is the client.py code that I am running:
import socket
import sys
sockett = socket.socket()
sockett.connect(('127.0.0.1', 123))
sockett.send(b'0')
print("Hello")
The doubt I have is that when I run the server.py (let S) file and then the client.py (let C) file, S keeps on running but C stops running which should be the case but the point at which S is stuck is the main problem. It prints 3 for the first time and then does not print anything, not 4 (so not out of the loop) not 1 (so not still looping). What could the reason be? Where is the code after it has printed 3?
This is the output I am getting:
12<socket......>(...)
b'0'
b''
3
_ (keeps on running indefinitely)
According to me, it should print 1 first, then 2, then run into an error which would be handled by try-except, and then print:
b''
b''
3
and then keep on looping like this.
The server is actually looping, but the reason you don't see the 1 or 2 when you're running this script is because you're not flushing your output:
import socket
import sys
sockett = socket.socket()
sockett.bind(('127.0.0.1', 123))
sockett.listen(10)
while True:
print('1', end='')
while True:
print('2', end='', flush=True)
try:
client, addr = sockett.accept()
print(client,addr)
break
except Exception as e:
print(e)
print(client.recv(400))
print(client.recv(1024))
print('3')
print('4')
You'll notice that with flush=True, in print('2', end='', flush=True) you'll see the 12 appear prior to the client's connection, and once again after the client disconnects.
12<socket...> (...)
b'0'
b''
3
12_ (keeps on running indefinitely)
With this, you can see that it's waiting again at client, addr = sockett.accept()
while True:
print('1', end='')
while True:
print('2', end='')
try:
client, addr = sockett.accept()
print(client,addr)
break
except Exception as e:
print(e)
This part will succeed (and not run into an error as you assume) once the client has connected.
print(client.recv(400))
This will read the b'0' send by the client.
print(client.recv(1024))
print('3')
This will wait for more data. Since the client closes the connection it will return with '', i.e. no data.
Then it will go to the beginning of the loop and from there into the inner loop where it is calling accept again. accept will block until it gets a new connection. Since you don't run the client again accept will block forever.
I am using aiozmq for a simple RPC program.
I have created a client and server.
When the server is running, the client runs just fine.
I have a timeout set in the client to raise an exception in the event of no server being reachable.
The client code is below. When I run it without the server running, I get an expected exception but the script doesn't actually return to the terminal. It still seems to be executing.
Could someone firstly explain how this is happening and secondly how to fix it?
import asyncio
from asyncio import TimeoutError
from aiozmq import rpc
import sys
import os
import signal
import threading
import sys
import traceback
#signal.signal(signal.SIGINT, signal.SIG_DFL)
async def client():
print("waiting for connection..")
client = await rpc.connect_rpc(
connect='tcp://127.0.0.1:5555',
timeout=1
)
print("got client")
for i in range(100):
print("{}: calling simple_add".format(i))
ret = await client.call.simple_add(1, 2)
assert 3 == ret
print("calling slow_add")
ret = await client.call.slow_add(3, 5)
assert 8 == ret
client.close()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.set_debug(True)
future = asyncio.ensure_future(client())
try:
loop.run_until_complete(future)
except TimeoutError:
print("Timeout occurred...")
future.cancel()
loop.stop()
#loop.run_forever()
main_thread = threading.currentThread()
for t in threading.enumerate():
if t is main_thread:
print("skipping main_thread...")
continue
print("Thread is alive? {}".format({True:'yes',
False:'no'}[t.is_alive()]))
print("Waiting for thread...{}".format(t.getName()))
t.join()
print(sys._current_frames())
traceback.print_stack()
for thread_id, frame in sys._current_frames().items():
name = thread_id
for thread in threading.enumerate():
if thread.ident == thread_id:
name = thread.name
traceback.print_stack(frame)
print("exiting..")
sys.exit(1)
#os._exit(1)
print("eh?")
The result of running the above is below. Note again that the program was still running, I had to to exit.
> python client.py
waiting for connection..
got client
0: calling simple_add
Timeout occurred...
skipping main_thread...
{24804: <frame object at 0x00000000027C3848>}
File "client.py", line 54, in <module>
traceback.print_stack()
File "client.py", line 60, in <module>
traceback.print_stack(frame)
exiting..
^C
I also tried sys.exit() which also didn't work:
try:
loop.run_until_complete(future)
except:
print("exiting..")
sys.exit(1)
I can get the program to die, but only if I use os._exit(1). sys.exit() doesn't seem to cut it. I doesn't appear that there are any other threads preventing the interpreter from dying. (Unless I'm mistaken?) What else could be stopping the program from exiting?
I'm using a socket to listen on a port in a while loop, with a 5 second timeout set by socket.settimeout(). But I have another method, which set's the listening port, and when called with a new port, i wanna force the socket to timeout so that I can reinitialise the socket and set the appropriate port inside the while loop. Is there a way to do that?
The socket is inside a subclass of threading.Thread
PS. Since this is my second day with Python, any other suggestions regarding any part would be most welcome. Thank you
EDIT:
I almost forgot. I want to reinitialise the socket when the setoutboundport method is called.
EDIT2
Man the whole code is messed up. I reexamined everything and it's really wrong for what I wanna achieve. Just focus on the main question. Timing out the socket.
import threading
import socket
import ResponseSender
import sys
import traceback
def __init__(self, inboundport, outboundip, outboundport, ttl=60):
super(Relay, self).__init__()
self.inboundport = inboundport
self.outboundip = outboundip
self.outboundport = outboundport
self.ttl = ttl
self.serverOn = True
self.firstpacket = True
self.sibling = None
self.newoutboundport = 0
self.listener = None
# ENDOF: __init__
def stop(self):
self.serverOn = False
# ENDOF: stop
def setsiblingrelay(self, relay):
self.sibling = relay
# ENDOF: setsiblingrelay
def setoutboundport(self, port):
self.newoutboundport = port
# ENDOF: setoutboundport
def run(self):
s = None
try:
while self.serverOn:
if not s:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
if self.outboundport != self.newoutboundport:
try:
s.close()
except:
pass
s.settimeout(4)
s.bind(('', self.inboundport))
print("Relay started :{0} => {1}:{2}".format(self.inboundport, self.outboundip, self.outboundport))
print("---------------------------------------- LISTENING FOR INCOMING PACKETS")
data, address = s.recvfrom(32768)
print("Received {0} from {1}:{2} => sending to {3}:{4}"
.format(data, address[0], address[1], self.outboundip, self.outboundport))
ResponseSender.sendresponse(address[0], address[1], data)
except TimeoutError:
pass
except:
print("Error: {0}".format(traceback.format_exception(*sys.exc_info())))
# ENDOF: run