Just to give some context: I'm currently learning Python and to do so I started a little Project.
I wrote two Python Scripts: a Host and a Client script.
I'm already at the point where multiple Clients can connect to one "Host" and the Host can send a random String to all Clients.
Now I wanted to solve the problem, that if a Client disconnects from the Host nobody knows until the CLIENTSOCKET is called again.
So I wrote the checkConnection method to ping all Clients every 5 sec, for now.
class Connection():
def __init__(self):
self.s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
def bound(self,RHOST,PORT):
self.s.bind((RHOST,PORT))
self.s.listen(1000)
def connect(self):
((CLIENTSOCKET,ADRESS)) = self.s.accept()
return (CLIENTSOCKET,ADRESS)
def newConnection(Connection,CLIENTS):
con = Connection
cli = CLIENTS
while True:
c = con.connect()
if c != None:
if len(cli) != 0:
for x in range (len(cli)):
if c[1][0] == cli[x][1][0]:
pass
else:
cli.append(c)
else:
cli.append(c)
def checkConnection(CLIENTS):
cli = CLIENTS
while True:
if(len(cli)!=0):
for x in range(len(cli)):
try:
cli[x][0].sendall(b'')
except:
del cli[x]
time.sleep(5)
I'm creating to Threads with each method as a target and give them the needed parameters. The first thread starts like it should, but the second doesn't.
I really don't know why?
t = threading.Thread(target = newConnection,name = "newConnection",args = (g,CLIENTS))
t2 = threading.Thread(target = checkConnection,name = "checkConnection",args = (CLIENTS))
t.start()
t2.start()
Exception in thread checkConnection:
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\threading.py", line 914, in _bootstrap_inner
self.run()
File "C:\Users\User\AppData\Local\Programs\Python\Python35-32\lib\threading.py", line 862, in run
self._target(*self._args, **self._kwargs)
TypeError: checkConnection() missing 1 required positional argument: 'CLIENTS'
Related
ErrorLog:
File "???\Python\Python38\lib\threading.py", line 932, in _bootstrap_inner
self.run()
File "???\Python\Python38\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "main.py", line 27, in th_listen_user
content = data.split('\n'.encode('utf-8'))[3]
IndexError: list index out of range
ServerCode:
import socket
import threading as th
server = socket.socket(
socket.AF_INET,
socket.SOCK_STREAM
)
server.bind(('127.0.0.1',8000))
server.listen(100)
USERS = {}
Exit = 0
def th_listen_user(user,adress):
try:
while True:
data = user.recv(2048)
ip = data.split('\n'.encode('utf-8'))[0].decode('utf-8')
port = int(data.split('\n'.encode('utf-8'))[1].decode('utf-8'))
part = data.split('\n'.encode('utf-8'))[2]
content = data.split('\n'.encode('utf-8'))[3]
print(data.split('\n'.encode('utf-8'))) #check Log
print(data)
print(ip,port,part,content)
except ConnectionResetError:print(f'<{adress[0]}:{adress[1]}> DISCONNECTED')
def start_server():
global Exit
while Exit==0:
user_socket,adress = server.accept()
print(f'<{adress[0]}:{adress[1]}> CONNECTED')
USERS[adress] = user_socket
th_func = th.Thread(target = th_listen_user,args = (user_socket,adress))
th_func.start()
print(USERS)
Log:
[b'127.0.0.1', b'9001', b'1', b'gAAAAABhitL94rJt4tAINg5Y1av_hY7YitgnrJD12pgNev6gjomZcYam9_VYQOZIR3Hyg-4mmPAyCKON2JZ3PSG9FHcQZLM_IyJZTAgFexlKc6UG1oVIBCo=']
b'127.0.0.1\n9001\n1\ngAAAAABhitL94rJt4tAINg5Y1av_hY7YitgnrJD12pgNev6gjomZcYam9_VYQOZIR3Hyg-4mmPAyCKON2JZ3PSG9FHcQZLM_IyJZTAgFexlKc6UG1oVIBCo='
127.0.0.1 9001 b'1' b'gAAAAABhitL94rJt4tAINg5Y1av_hY7YitgnrJD12pgNev6gjomZcYam9_VYQOZIR3Hyg-4mmPAyCKON2JZ3PSG9FHcQZLM_IyJZTAgFexlKc6UG1oVIBCo='
I am writing a chat application. There was a problem with the server. He swears at a non-existent mistake.
The error is displayed after the code is executed without errors.
And as I understand it, it is somehow connected with sockets.
What does this error mean and how to avoid it ?
I am running a web server on a raspberry pi which is logging temperatures etc.
I am using websockets in Tornado to communicate with my client.
I want the client to be able to control when the server is sending data over the socket.
My thought was that when client connects and says it's ready, the server will start a loop where it logs temps every second. But I need this loop to run asynchronously. This is where I get in trouble. I tried to follow an example, but I cant get it to run properly.
class TemperatureSocketHandler(tornado.websocket.WebSocketHandler):
#gen.coroutine
def async_func(self):
num = 0
while(self.sending):
num = num + 1
temp = self.sense.get_temperature()
yield self.write_message(str(temp))
gen.sleep(1)
def open(self):
print("Temperature socket opened")
self.sense = SenseHat()
self.sense.clear()
self.sending = False
def on_message(self, message):
if(message == "START"):
self.sending = True
if(message == "STOP"):
self.sending = False
tornado.ioloop.IOLoop.current().spawn_callback(self.async_func(self))
But I get an error here when I run this:
ERROR:tornado.application:Exception in callback functools.partial(<function wrap.<locals>.null_wrapper at 0x75159858>)
Traceback (most recent call last):
File "/home/pi/.local/lib/python3.5/site-packages/tornado/ioloop.py", line 605, in _run_callback
ret = callback()
File "/home/pi/.local/lib/python3.5/site-packages/tornado/stack_context.py", line 277, in null_wrapper
return fn(*args, **kwargs)
TypeError: 'Future' object is not callable
You have to use IOLoop.add_future()
since async_func() returns a Future (it is decorated as a coroutine!).
Also, you should add the future, when you receive the start message, not on any message:
def on_message(self, message):
if(message == "START"):
self.sending = True
tornado.ioloop.IOLoop.current().add_future(
self.async_func(self), lambda f: self.close())
if(message == "STOP"):
self.sending = False
Using Pyro4 I haven't managed to successfully execute a callback from server to client.
The server script looks as follows:
class RobotController(object):
def __init__(self):
self.robotStates = []
def moveDemo(self, motionTime):
stopTime = datetime.datetime.now() + datetime.timedelta(0,motionTime)
while datetime.datetime.now() < stopTime:
print "Robot is moving..."
time.sleep(1)
print "Robot stopped"
return 0
def doCallback(self, callback):
print("server: doing callback 1 to client")
try:
callback.call1()
except:
print("got an exception from the callback.")
print("".join(Pyro4.util.getPyroTraceback()))
print("server: doing callback 2 to client")
try:
callback.call2()
except:
print("got an exception from the callback.")
print("".join(Pyro4.util.getPyroTraceback()))
print("server: callbacks done")
if __name__ == '__main__':
robotController = RobotController()
if os.name == 'posix':
daemon = Pyro4.Daemon(host="192.168.1.104", port=8000);
else:
daemon = Pyro4.Daemon(host="localhost", port=8000);
Pyro4.Daemon.serveSimple(
{ robotController: "robotController"},
ns=False,
daemon=daemon,
verbose = True
)
and the client looks as follows:
class CallbackHandler(object):
def crash(self):
a=1
b=0
return a//b
def call1(self):
print("callback 1 received from server!")
print("going to crash - you won't see the exception here, only on the server")
return self.crash()
#Pyro4.callback
def call2(self):
print("callback 2 received from server!")
print("going to crash - but you will see the exception here too")
return self.crash()
daemon = Pyro4.core.Daemon()
callback = CallbackHandler()
daemon.register(callback)
#robotController = Pyro4.Proxy("PYRO:robotController#192.168.1.104:8000")
robotController = Pyro4.Proxy("PYRO:robotController#localhost:8000")
robotController._pyroOneway.add("doCallback")
robotController.doCallback(callback)
When executing the command robotController.doCallback(callback), the method doCallback on server is executed, but the server cannot access the client. It returns the following:
Traceback (most recent call last):
File "C:\LASTNO\Python Projects\PiBot\RobotServer\PyroServer\pyroServer.py", line 63, in doCallback
callback.call2()
File "C:\Python27\lib\site-packages\Pyro4\core.py", line 160, in __call__
return self.__send(self.__name, args, kwargs)
File "C:\Python27\lib\site-packages\Pyro4\core.py", line 286, in _pyroInvoke
self.__pyroCreateConnection()
File "C:\Python27\lib\site-packages\Pyro4\core.py", line 371, in __pyroCreateConnection
raise ce
CommunicationError: cannot connect: [Errno 10061] No connection could be made because the target machine actively refused it
Does anyone know what could be the cause of the error and how to fix it? Thank you!
I solved the problem by modifying the client code as follows:
class CallbackHandler(object):
def crash(self):
a=1
b=0
return a//b
def call1(self):
print("callback 1 received from server!")
print("going to crash - you won't see the exception here, only on the server")
return self.crash()
#Pyro4.callback
def call2(self):
print("callback 2 received from server!")
print("going to crash - but you will see the exception here too")
return self.crash()
daemon = Pyro4.core.Daemon()
callback = CallbackHandler()
daemon.register(callback)
with Pyro4.core.Proxy("PYRO:robotController#localhost:8000") as server:
server._pyroOneway.add("doCallback")
server.doCallback(callback)
motion = server.moveDemo(15)
print("waiting for callbacks to arrive...")
print("(ctrl-c/break the program once it's done)\n")
daemon.requestLoop()
Say I want to ping something from different locations, so I wrap ping commandline tool into python and use pyro4 prc library to call it.
I have a python Pyro4 nameserver
import Pyro4
Pyro4.config.COMPRESSION = True
Pyro4.naming.startNSloop("ipofnameserver")
And simple ping server:
class Pinger(object):
def ping(self, host):
return subprocess.check_output(["ping", host, "-c 4"])
pinger = Pinger()
daemon = Pyro4.Daemon() # make a Pyro daemon
ns = Pyro4.locateNS(host = "ipofnameservre", port=9090) # find the name server
uri = daemon.register(pinger) # register the greeting object as a Pyro object
print ns.register("location1", uri)
print "Ready. Object uri =", uri # print the uri so we can use it in the client later
daemon.requestLoop()
As long as I have only two pingservers everything is ok, but after I add third one nameserver stop responding. Every pingserver has unique name of course.
For example, I want to check availability of the servers:
ns = Pyro4.locateNS(host = "nameserverip", port=9090)
names = ns.list().keys()
print names
print ns.list()
for n in names:
if n == 'Pyro.NameServer': continue
proxy = Pyro4.Proxy("PYRONAME:"+n)
try:
print n, proxy._Proxy__pyroCreateConnection()
except:
print "offline"
This works with two pingservers, but with three it just waits for something. Traceback of this script terminated with ctrl+C:
ns = Pyro4.locateNS(host = "nameserverip", port=9090)
File "/usr/local/lib/python2.7/dist-packages/Pyro4/naming.py", line 319, in locateNS
proxy.ping()
File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 146, in __call__
return self.__send(self.__name, args, kwargs)
File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 250, in _pyroInvoke
self.__pyroCreateConnection()
File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 312, in __pyroCreateConnection
msgType, flags, seq, data = MessageFactory.getMessage(conn, None)
File "/usr/local/lib/python2.7/dist-packages/Pyro4/core.py", line 665, in getMessage
headerdata = connection.recv(cls.HEADERSIZE)
File "/usr/local/lib/python2.7/dist-packages/Pyro4/socketutil.py", line 323, in recv
return receiveData(self.sock, size)
File "/usr/local/lib/python2.7/dist-packages/Pyro4/socketutil.py", line 104, in receiveData
data=sock.recv(size, socket.MSG_WAITALL)
strace shows the following:
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 3 fcntl(3, F_GETFL)
= 0x2 (flags O_RDWR) fcntl(3, F_SETFL, O_RDWR) = 0 connect(3, {sa_family=AF_INET, sin_port=htons(9090),
sin_addr=inet_addr("ipofnameserver")}, 16) = 0 setsockopt(3,
SOL_SOCKET, SO_KEEPALIVE, [1], 4) = 0 recvfrom(3,
The following example is not working either, as it unable to resolve names into pyro_uri, because it just waits for something like in previous example. Interesting thing about this example that it prints fls, which contains names of all remote pingservers. Then adding fourth pingserver I'm unable even to print names of registered pingservers.
def _ping((host, firing_location)):
pinger = Pyro4.Proxy("PYRONAME:" + firing_location)
return pinger.ping(host)
def ping(host):
ns = Pyro4.locateNS(host = "178.209.52.240", port=9090)
names = ns.list().keys()
fls = []
for name in names:
if name == 'Pyro.NameServer': continue
fls.append(name)
print fls
p = Pool(len(fls))
jobs = p.map(_ping, zip([host]*len(fls), fls) )
for j in jobs:
print j.split("/")[-3], "±", j.split("/")[-1][:-1]
return jobs
I'm struggling with it for two days and have no idea of what's wrong with my code.
I've written a threaded websocket server in Python, using the lastest websocket spec and I'm trying to make it send a ping request to every client every x seconds. The only way I came up with to do this is overriding BaseServer.server_forever() like this:
# override BaseServer's serve_forever to send a ping request every now and then
class ModTCPServer(SocketServer.TCPServer):
def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
self.__is_shut_down = threading.Event()
self.__shutdown_request = False
def serve_forever(self, poll_interval=0.5):
###
global PING_EVERY_SEC
self.lastPing = int(time())
###
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
r, w, e = select.select([self], [], [], poll_interval)
if self in r:
self._handle_request_noblock()
###
now = int(time())
if (now - self.lastPing) >= PING_EVERY_SEC:
self.socket.send(WebSocketPing(['0x89','0x21','0xa7','0x4b'], now)) # arbitrary key
self.lastPing = now
###
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
class LoginServer(SocketServer.ThreadingMixIn, ModTCPServer):
pass
server = LoginServer(("", PORT), ApplicationHandler)
print "serving at port", PORT
server_thread = threading.Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
while server_thread.isAlive():
pass
server.shutdown()
Here is the function that constructs the Ping frame, it just puts the timestamp in the contents:
def WebSocketPing(key, timestamp=False):
data = ['0x89','0x8a'] # 0x89 = fin,ping 0x8a = masked,len=10
data.extend(key)
if timestamp:
t = str(timestamp)
else:
t = str(int(time()))
for i in range(10):
masking_byte = int(key[i%4],16)
masked = ord(t[i])
data.append(hex(masked ^ masking_byte))
frame = ''
for i in range(len(data)):
frame += chr(int(data[i],16))
return frame
Bad things happen when I run this
Traceback (most recent call last):
File "LoginServer.py", line 91, in <module>
server = LoginServer(("", PORT), ApplicationHandler)
File "LoginServer.py", line 63, in __init__
SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass, bind_and_activate)
File "/usr/lib/python2.6/SocketServer.py", line 400, in __init__
self.server_bind()
File "/usr/lib/python2.6/SocketServer.py", line 411, in server_bind
self.socket.bind(self.server_address)
File "<string>", line 1, in bind
socket.error: [Errno 112] Address already in use
I assume this is down to my lack of understanding of how overriding works in Python or to a fundamentally wrong approach to this problem. Is there a better way to do this or a way to make this code work?
The codes does not set the properties __is_shut_down and __shutdown_request anywhere. Therefore, trying to access them fails. Create them in the constructor, like this:
class ModTCPServer(SocketServer.TCPServer):
def __init__(self, *args, **kwargs):
SocketServer.TCPServer.__init__(self, *args, **kwargs)
self.__is_shut_down = threading.Event()
self.__shutdown_request = threading.Event()
In response to the update:
socket.error: [Errno 112] Address already in use
means that another process has already bound to the specified port. On Unix, you can find that process with sudo netstat -ltpn. Alternatively, choose a different port.