Python Pika callback is not working with SelectConnection inside a class - python

I am trying to create a simple Python Pika SelectConnection and it seems that I am not able to open a connection using the on_open_callback and I don't get anything from te on_open_error_callback either. Can someone suggest what might be causing the problem?
import pika
class RabbitmqTransport(object):
def __init__(self):
self._connection = None
self._channel = None
self._connect()
def on_connection_open(self):
print "connection created"
def on_connection_open_error(self):
print "connection open error"
def _connect(self):
# Setup RabbitMQ connection
credentials = pika.PlainCredentials('guest','guest')
parameters = pika.URLParameters('amqp://guest:guest#localhost:5672/%2F')
print "Creating Connection"
self._connection = pika.SelectConnection(parameters=parameters,on_open_callback=self.on_connection_open,on_open_error_callback=self.on_connection_open_error)
print self._connection.connection_state
print dir(self._connection)
print self._connection.is_open
r = RabbitmqTransport()

Found the problem, I added the line bellow and then connection was opened and the callback worked.
self._connection.ioloop.start()

Related

exceptions.AttributeError: EchoFactory instance has no attribute 'connection'

First of all I would like to say that I just got started with both python and twisted so even being searching for all the errors and doubts that I have I'm sure I can still produce some silly ones.
Said that, I'm working on this client-server pair, where the client will simulate a listening loop to know if a device is connected to it and then send a message to the server with it's parameters.
First I was creating the connection, then started the loop and after that sent the file once the device was connected (you'll see that commented at the bottom of the code). Now what I'm trying to do is to create the connection when the device is connected to the client (inside the function called by LoopingCall), and here comes the problem as it throws the exception that you see in the title.
This is the client code, which is the one that is giving me troubles.
from twisted.internet import reactor, protocol
from twisted.internet.task import LoopingCall
import gri
import os
ID = '1258'
filename = 'parameters.xml'
a = 1;
reg = 0;
xreg = 0;
xdreg = 0;
#Create the radio object
radio = gri.Radio()
class EchoClient(protocol.Protocol):
def connectionMade(self):
self.transport.write(ID)
def sendXML(self):
f = open(filename,'r')
self.transport.write(f.read())
f.close()
class EchoFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
self.connection = EchoClient()
return self.connection
def clientConnectionFailed(self, connector, reason):
print "Connection failed."
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost."
reactor.stop()
#listening loop
def find_usrp():
global a
global reg
global xreg
global xdreg
global factory
# a=0 if the device is connected, a=1 if not
a = radio.findRadio()
if a == 0:
reg = 1
if xreg == 0:
#creating the connection once the device is connected
factory = EchoFactory()
reactor.connectTCP("localhost",8000, factory)
factory.connection.sendXML()
xreg = 1
xdreg = 0
else:
print "Device is not connected"
if reg == 1:
print "Device is out"
if xdreg == 0:
xdreg = 1
xreg = 0
#creating the connection before the loop
#factory = EchoFactory()
#reactor.connectTCP("localhost",8000, factory)
LoopingCall(find_usrp).start(1, now = False)
reactor.run()
So that's it, I don't know why when it goes to factory.connection.sendXML() it doesn't find the connection. I've been trying different things like passing factory as a parameter to find_usrp function, changing things of place but I'm afraid I don't have enough knowledge in this language to know what is really going on... Let's see if you can help me with this so I can really learn about it. Thanks!
Edit:
So far what eighilaza says make sense to me, I've tried to run this line
factory.connection.sendXML()
some time after and it seems that it works, so maybe I'm trying to run this function before it's created. But is there any way to control this?
What causes your error is that you call factory.connection before the connection is made.
In your code reactor.connectTCP("localhost",8000, factory) is non-blocking so you reach factory.connection.sendXML() before the connection is made.

Pymodbus/Twisted Asynchronous Client Reconnecting

I have written a test code which reads some coils/registers from a PLC's modbus server. When I call one request the code works. I unplugged the cable then Twisted calls clientConnectionLost function so my client will reconnected, when I plugged back the cable. If I do multiple requests, like in the code below, the handling breaks, nothing happens. I don't know what causes the problem.
#!/usr/bin/env python
from PyQt4 import QtCore, QtGui
from twisted.internet import reactor, protocol,defer
from pymodbus.constants import Defaults
from pymodbus.client.async import ModbusClientProtocol
from time import sleep
def logger():
import logging
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)
logger()
class MyModbusClientProtocol(ModbusClientProtocol):
def connectionMade(self):
ModbusClientProtocol.connectionMade(self)
print 'Connected'
self.read()
def read(self):
deferred = self.read_coils(0,1999)
deferred.addCallbacks(self.requestFetched,self.requestNotFetched)
deferred = self.read_holding_registers(0,124)
deferred.addCallbacks(self.requestFetched,self.requestNotFetched)
def requestNotFetched(self,error):
print error
sleep(0.5)
def requestFetched(self,response):
try:
print ("Fetched %d" % response.getRegister(1))
except:
print ("Fetched %d" % response.getBit(1))
self.factory.counter += 1
if self.factory.counter == 2:
self.factory.counter = 0
reactor.callLater(0,self.read)
class MyModbusClientFactory(protocol.ClientFactory):
"""A factory.
A new protocol instance will be created each time we connect to the server.
"""
def __init__(self):
self.counter = 0
def buildProtocol(self, addr):
p = MyModbusClientProtocol()
p.factory = self
return p
def clientConnectionLost(self, connector, reason):
print "connection lost:", reason
connector.connect()
def clientConnectionFailed(self, connector, reason):
print "connection failed:", reason
connector.connect()
if __name__ == "__main__":
factoryinstance = MyModbusClientFactory()
reactor.connectTCP("192.168.2.69", 502, factoryinstance)
reactor.run()
I have tested your code and believe that you have seen a timing related red herring when your code was seen to work after commenting out one of your requests. The behavior you are seeing where clientConnectionLost is not called is covered in the twisted FAQ: Why isn't my connectionLost method called?
What you need to do is create your own protocol specific timeout as you can't always rely on TCP's timeouts to work in your favor. A simple way to fix your code would be to add this to the end of your read method:
self.timeout = reactor.callLater(5, self.transport.abortConnection)
Which will abort the connection after 5 seconds wait. You also need to cancel this timeout when your requests have completed successfully with:
self.timeout.cancel()
in your requestFetched method before you call your read again.

Python Chat Server - Telnet error

I have the following code which is supposed to implement a basic chat server on my localhost. The code has no errors (i dont get any erros thrown at me when i run the code). However when i run the program using telnet , i always get the error :
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
I have made sure that the port i am trying to connect to is open. I am trying this out on Ubuntu 12.04. I have installed telnet. The code is as follows:
from asyncore import dispatcher
from asynchat import async_chat
import socket, asyncore
PORT = 5939
NAME = 'Chatbox'
class ChatSession(async_chat):
def __init__(self,server,sock):
async_chat.__init__(self, sock)
self.server = server
self.set_terminator("\r\n")
self.data = []
def collect_incoming_data(self, data):
self.data.append(data)
def found_terminator(self):
line =''.join(self.data)
self.data = []
self.server.broadcast(line)
def handle_close(self):
async_chat.handle_close(self)
self.server.disconnect(self)
class ChatServer(dispatcher):
def __init__(self, port, name):
dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('',port))
self.listen(5)
self.name = name
self.sessions = []
def disconnect(self, sessions):
self.sessions.remove(session)
def broadcast(self, line):
for session in self.sessions:
session.push('>>' + line + '\r\n')
def handle_accept(self):
conn, addr = self.accept()
self.sessions.append(ChatSession(self, conn))
if __name__ == '__main__':
s = ChatServer(PORT, NAME)
try: asyncore.loop()
except KeyboardInterrupt: print
I run the programs using the commands :
user#ubuntu:~$ python chatbox.py
user#ubuntu:~$ telnet 127.0.0.1 5939
I am pretty sure its a minor issue in executing the program but I havent used linux before so I am unsure if my process is correct. Any help will b appreciated.
UPDATE: Ok so there where a few formatting errors in my code which i solved. Now when I run the code, the terminal goes unresponsive.
The code works perfectly except one thing. When client disconnect, following exception is raised:
....
File "t.py", line 25, in handle_close
self.server.disconnect(self)
File "t.py", line 38, in disconnect
self.sessions.remove(session)
NameError: global name 'session' is not defined
ChatServer.disconnect should be: (parameter name should be session, sessions)
def disconnect(self, session):
self.sessions.remove(session)

Python Socket connection class

I'm trying to create a small program that will log information output from a device via TCP
Basically this just streams data out, that i want to capture, and dump into a database for dealing with later
but the device reboots so i need to be able to reconnect when the socket closes with out any human interference
so this is what i have so far
import socket, time, logging, sys, smtplib # Import socket module
logging.basicConfig(filename='Tcplogger.log',level=logging.DEBUG,format='%(asctime)s : %(levelname)s : %(message)s')
logging.info('|--------------------------------------|')
logging.info('|--------------- TCP Logger Starting---|')
logging.info('|--------------------------------------|')
host = '127.0.0.01' # host or Ip address
port = 12345 # output port
retrytime = 1 # reconnect time
reconnectattemps = 10 # Number of time to try and reconnect
class TPCLogger:
def __init__(self):
logging.debug('****Trying connection****')
print('****Trying connection****')
self.initConnection()
def initConnection(self):
s = socket.socket()
try:
s.connect((host, port))
logging.debug('****Connected****')
except IOError as e:
while 1:
reconnectcount = 0;
logging.error(format(e.errno)+' : '+format(e.strerror))
while 1:
reconnectcount = reconnectcount + 1
logging.error('Retrying connection to Mitel attempt : '+str(reconnectcount))
try:
s.connect((host, port))
connected = True
logging.debug('****Connected****')
except IOError as e:
connected = False
logging.error(format(e.errno)+' : '+format(e.strerror))
if reconnectcount == reconnectattemps:
logging.error('******####### Max Reconnect attempts reached logger will Terminate ######******')
sys.exit("could Not connect")
time.sleep(retrytime)
if connected == True:
break
break
while 1:
s.recv(1034)
LOGGER= TCPLogger()
Which all works fine on start up if a try to connect and its not there it will retry the amount of times set by reconnectattemps
but he is my issue
while 1:
s.recv(1034)
when this fails i want to try to reconnect
i could of course type out or just copy my connection part again but what i want to be able todo is call a function that will handle the connection and retry and hand me back the connection object
for example like this
class tcpclient
#set some var
host, port etc....
def initconnection:
connect to socket and retry if needed
RETURN SOCKET
def dealwithdata:
initconnection()
while 1:
try:
s.recv
do stuff here copy to db
except:
log error
initconnection()
I think this is possible but im really not geting how the class/method system works in python so i think im missing something here
FYI just in case you didn't notice iv very new to python. any other comments on what i already have are welcome too :)
Thanks
Aj
Recommendation
For this use-case I would recommend something higher-level than sockets. Why? Controlling all these exceptions and errors for yourself can be irritating when you just want to retrieve or send data and maintain connection.
Of course you can achieve what you want with your plain solution, but you mess with code a bit more, methinks. Anyway it'll look similarly to class amustafa wrote, with handling socket errors to close/reconnect method, etc.
Example
I made some example for easier solution using asyncore module:
import asyncore
import socket
from time import sleep
class Client(asyncore.dispatcher_with_send):
def __init__(self, host, port, tries_max=5, tries_delay=2):
asyncore.dispatcher.__init__(self)
self.host, self.port = host, port
self.tries_max = tries_max
self.tries_done = 0
self.tries_delay = tries_delay
self.end = False # Flag that indicates whether socket should reconnect or quit.
self.out_buffer = '' # Buffer for sending.
self.reconnect() # Initial connection.
def reconnect(self):
if self.tries_done == self.tries_max:
self.end = True
return
print 'Trying connecting in {} sec...'.format(self.tries_delay)
sleep(self.tries_delay)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
try:
self.connect((self.host, self.port))
except socket.error:
pass
if not self.connected:
self.tries_done += 1
print 'Could not connect for {} time(s).'.format(self.tries_done)
def handle_connect(self):
self.tries_done = 0
print 'We connected and can get the stuff done!'
def handle_read(self):
data = self.recv(1024)
if not data:
return
# Check for terminator. Can be any action instead of this clause.
if 'END' in data:
self.end = True # Everything went good. Shutdown.
else:
print data # Store to DB or other thing.
def handle_close(self):
print 'Connection closed.'
self.close()
if not self.end:
self.reconnect()
Client('localhost', 6666)
asyncore.loop(timeout=1)
reconnnect() method is somehow core of your case - it's called when connection is needed to be made: when class initializes or connection brokes.
handle_read() operates any recieved data, here you log it or something.
You can even send data using buffer (self.out_buffer += 'message'), which will remain untouched after reconnection, so class will resume sending when connected again.
Setting self.end to True will inform class to quit when possible.
asyncore takes care of exceptions and calls handle_close() when such events occur, which is convenient way of dealing with connection failures.
You should look at the python documentation to understand how classes and methods work. The biggest difference between python methods and methods in most other languages is the addition of the "self" tag. The self represents the instance that a method is called against and is automatically fed in by the python system. So:
class TCPClient():
def __init__(self, host, port, retryAttempts=10 ):
#this is the constructor that takes in host and port. retryAttempts is given
# a default value but can also be fed in.
self.host = host
self.port = port
self.retryAttempts = retryAttempts
self.socket = None
def connect(self, attempt=0):
if attempts<self.retryAttempts:
#put connecting code here
if connectionFailed:
self.connect(attempt+1)
def diconnectSocket(self):
#perform all breakdown operations
...
self.socket = None
def sendDataToDB(self, data):
#send data to db
def readData(self):
#read data here
while True:
if self.socket is None:
self.connect()
...
Just make sure you properly disconnect the socket and set it to None.

How make a twisted python client with readline functionality

I'm trying to write a client for simple TCP server using Python Twisted. Of course I pretty new to Python and just started looking at Twisted so I could be doing it all wrong.
The server is simple and you're intended to use use nc or telnet. There is no authentication. You just connect and get a simple console. I'd like to write a client that adds some readline functionality (history and emacs like ctrl-a/ctrl-e are what I'm after)
Below is code I've written that works just as good as using netcat from the command line like this nc localhost 4118
from twisted.internet import reactor, protocol, stdio
from twisted.protocols import basic
from sys import stdout
host='localhost'
port=4118
console_delimiter='\n'
class MyConsoleClient(protocol.Protocol):
def dataReceived(self, data):
stdout.write(data)
stdout.flush()
def sendData(self,data):
self.transport.write(data+console_delimiter)
class MyConsoleClientFactory(protocol.ClientFactory):
def startedConnecting(self,connector):
print 'Starting connection to console.'
def buildProtocol(self, addr):
print 'Connected to console!'
self.client = MyConsoleClient()
self.client.name = 'console'
return self.client
def clientConnectionFailed(self, connector, reason):
print 'Connection failed with reason:', reason
class Console(basic.LineReceiver):
factory = None
delimiter = console_delimiter
def __init__(self,factory):
self.factory = factory
def lineReceived(self,line):
if line == 'quit':
self.quit()
else:
self.factory.client.sendData(line)
def quit(self):
reactor.stop()
def main():
factory = MyConsoleClientFactory()
stdio.StandardIO(Console(factory))
reactor.connectTCP(host,port,factory)
reactor.run()
if __name__ == '__main__':
main()
The output:
$ python ./console-console-client.py
Starting connection to console.
Connected to console!
console> version
d305dfcd8fc23dc6674a1d18567a3b4e8383d70e
console> number-events
338
console> quit
I've looked at
Python Twisted integration with Cmd module
This really didn't work out for me. The example code works great but when I introduced networking I seemed to have race conditions with stdio. This older link seems to advocate a similar approach (running readline in a seperate thread) but I didn't get far with it.
I've also looked into twisted conch insults but I haven't had any luck getting anything to work other than the demo examples.
What's the best way to make a terminal based client that would provide readline support?
http://twistedmatrix.com/documents/current/api/twisted.conch.stdio.html
looks promising but I'm confused how to use it.
http://twistedmatrix.com/documents/current/api/twisted.conch.recvline.HistoricRecvLine.html
also seems to provide support for handling up and down arrow for instance but I couldn't get switching Console to inherit from HistoricRecVLine instead of LineReceiver to function.
Maybe twisted is the wrong framework to be using or I should be using all conch classes. I just liked the event driven style of it. Is there a better/easier approach to having readline or readline like support in a twisted client?
I landed up solving this by not using the Twisted framework. It's a great framework but I think it was the wrong tool for the job. Instead I used the telnetlib, cmd and readline modules.
My server is asynchronous but that didn't mean my client needed to be so I used telnetlib for my communication to the server. This made it easy to create a ConsoleClient class which subclasses cmd.Cmd and get history and emacs-like shortcuts.
#! /usr/bin/env python
import telnetlib
import readline
import os
import sys
import atexit
import cmd
import string
HOST='127.0.0.1'
PORT='4118'
CONSOLE_PROMPT='console> '
class ConsoleClient(cmd.Cmd):
"""Simple Console Client in Python. This allows for readline functionality."""
def connect_to_console(self):
"""Can throw an IOError if telnet connection fails."""
self.console = telnetlib.Telnet(HOST,PORT)
sys.stdout.write(self.read_from_console())
sys.stdout.flush()
def read_from_console(self):
"""Read from console until prompt is found (no more data to read)
Will throw EOFError if the console is closed.
"""
read_data = self.console.read_until(CONSOLE_PROMPT)
return self.strip_console_prompt(read_data)
def strip_console_prompt(self,data_received):
"""Strip out the console prompt if present"""
if data_received.startswith(CONSOLE_PROMPT):
return data_received.partition(CONSOLE_PROMPT)[2]
else:
#The banner case when you first connect
if data_received.endswith(CONSOLE_PROMPT):
return data_received.partition(CONSOLE_PROMPT)[0]
else:
return data_received
def run_console_command(self,line):
self.write_to_console(line + '\n')
data_recved = self.read_from_console()
sys.stdout.write(self.strip_console_prompt(data_recved))
sys.stdout.flush()
def write_to_console(self,line):
"""Write data to the console"""
self.console.write(line)
sys.stdout.flush()
def do_EOF(self, line):
try:
self.console.write("quit\n")
self.console.close()
except IOError:
pass
return True
def do_help(self,line):
"""The server already has it's own help command. Use that"""
self.run_console_command("help\n")
def do_quit(self, line):
return self.do_EOF(line)
def default(self, line):
"""Allow a command to be sent to the console."""
self.run_console_command(line)
def emptyline(self):
"""Don't send anything to console on empty line."""
pass
def main():
histfile = os.path.join(os.environ['HOME'], '.consolehistory')
try:
readline.read_history_file(histfile)
except IOError:
pass
atexit.register(readline.write_history_file, histfile)
try:
console_client = ConsoleClient()
console_client.prompt = CONSOLE_PROMPT
console_client.connect_to_console()
doQuit = False;
while doQuit != True:
try:
console_client.cmdloop()
doQuit = True;
except KeyboardInterrupt:
#Allow for ^C (Ctrl-c)
sys.stdout.write('\n')
except IOError as e:
print "I/O error({0}): {1}".format(e.errno, e.strerror)
except EOFError:
pass
if __name__ == '__main__':
main()
One change I did was remove the prompt returned from the server and use Cmd.prompt to display to the user. I reason was to support Ctrl-c acting more like a shell.

Categories