I'm trying to build a client/server system that clients send messages to server. Server does nothing more than printing out what clients send.
from twisted.internet import protocol, reactor
class Echo(protocol.Protocol):
def dataReceived(self, data):
print data
self.transport.write(data)
class EchoFactory(protocol.Factory):
def buildProtocol(self, addr):
return Echo()
reactor.listenTCP(8000, EchoFactory())
reactor.run()
The issue is that when I tried to send multiple message from client with this code, the client raises an error after the first connection and send.
from twisted.internet import reactor, protocol
import time
class EchoClient(protocol.Protocol):
def __init__(self, message):
self.message = message
def connectionMade(self):
self.transport.write(self.message)
def dataReceived(self, data):
print "Server said:", data
self.transport.loseConnection()
class EchoFactory(protocol.ClientFactory):
def __init__(self, message):
self.message = message
def buildProtocol(self, addr):
return EchoClient(self.message)
def clientConnectionFailed(self, connector, reason):
print "Connection failed."
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost."
reactor.stop()
def sendMessage(message):
reactor.connectTCP("localhost", 8000, EchoFactory(message))
reactor.run()
if __name__ == "__main__":
while True:
r = raw_input(">")
if r == 'q' or len(r) == 0: break
sendMessage(r)
What might be wrong? this is the error message.
>a
Server said: a
Connection lost.
>b
Traceback (most recent call last):
File "echoclient.py", line 38, in <module>
sendMessage(r)
File "echoclient.py", line 32, in sendMessage
reactor.run()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/base.py", line 1168, in run
self.startRunning(installSignalHandlers=installSignalHandlers)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/base.py", line 1148, in startRunning
ReactorBase.startRunning(self)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/twisted/internet/base.py", line 680, in startRunning
raise error.ReactorNotRestartable()
twisted.internet.error.ReactorNotRestartable
Although this question is old and has two irrelevant answers, I would like to answer it for the people who are eager to know. The problem is that in your server code in the dataReceived method you have self.transport.write(data) (which sends every message that it receives to the client), and at the same time in your client code, again in the dataReceived method you have the command self.transport.loseConnection() (which looses the connection to the server as soon as a message comes in). So, if you remove any of these lines you should be fine. In the current setting the first message sent from client will be sent back to the client and that will cause a connection disconnect.
Also, you are calling reactor.run () at each attempt for sending a message. Reactor.run should be called only once preferably in the main function.
The reactor is not restartable.
For my own purposes, using socket to send messages to server works fine.
import socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect(('localhost', 8000))
while True:
a = raw_input("> ")
if a == 'q' or len(a) == 0:
client_socket.close()
break
else:
client_socket.send(a)
Related
I have a very basic twisted server/client setup in python.
server.py:
from twisted.internet.protocol import Protocol
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.internet import reactor
class Echo(Protocol):
def __init__(self, factory):
self.factory = factory
def connectionMade(self):
print("Connection made")
def connectionLost(self):
print("Connection lost")
def dataReceived(self, data):
print("Received data")
print(data)
self.transport.write(data)
class EchoFactory(Factory):
def buildProtocol(self, addr):
return Echo(self)
def main():
PORT = 9009 #the port you want to run under. Choose something >1024
endpoint = TCP4ServerEndpoint(reactor, PORT)
endpoint.listen(EchoFactory())
reactor.run()
if __name__ == "__main__":
main()
client.py:
from twisted.internet import reactor
from twisted.internet.protocol import Protocol
from twisted.internet.endpoints import TCP4ClientEndpoint, connectProtocol
class Greeter(Protocol):
def sendMessage(self, msg):
print('sending message')
self.transport.write("MESSAGE %s\n" % msg)
print('message sent')
def gotProtocol(p):
p.sendMessage("Hello")
reactor.callLater(1, p.sendMessage, "This is sent in a second")
reactor.callLater(2, p.transport.loseConnection)
PORT = 9009
point = TCP4ClientEndpoint(reactor, "localhost", PORT)
d = connectProtocol(point, Greeter())
d.addCallback(gotProtocol)
print('running reactor')
reactor.run()
The server works just fine as I've pinged it with a Telnet client and receive the expected response. However when I try and run client.py it gets stuck at "self.transport.write("MESSAGE %s\n" % msg)". Or at least I assume it does as the last thing printed to console is 'sending message'.
I've searched for days but can't seem to figure out what's wrong (I'm rather new to networking). What am I doing wrong here? I'm using Python 3 and running Windows 8.1.
It doesn't get stuck at self.transport.write("MESSAGE %s\n" % msg) it actually fails there. Transport.write only accepts bytes. Encode the string and it should work.
class Greeter(Protocol):
def sendMessage(self, msg):
print('sending message')
self.transport.write(("MESSAGE %s\n" % msg).encode('utf8'))
print('message sent')
I have the following code:
# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
An example client. Run simpleserv.py first before running this.
"""
from twisted.internet import reactor, protocol
# a client protocol
class EchoClient(protocol.Protocol):
"""Once connected, send a message, then print the result."""
def connectionMade(self):
self.transport.write("Welcome to Calculator!")
# data = ''
def dataReceived(self, data):
"As soon as any data is received, write it back."
print "Server said:\n", data
# self.transport.loseConnection()
def connectionLost(self, reason):
print "connection lost"
class EchoFactory(protocol.ClientFactory):
protocol = EchoClient
def clientConnectionFailed(self, connector, reason):
print "Connection failed - goodbye!"
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost - goodbye!"
reactor.stop()
# this connects the protocol to a server running on port 8000
def main():
help(protocol.Protocol)
exit()
f = EchoFactory()
reactor.connectTCP("localhost", 8000, f)
reactor.run()
print 'here'
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
What is the correct way to read client input and send it to server? I want to read the data using data = input() and after it send to server self.transport.write(data). But, where I have to put it on my code, do I have to create another method or use connectionMade?
Remembering, that is a persistent connection where client send something to server, then the server process it and send something to client. And again client send something to server, server process it and send to client... (repeatedly)
def connectionMade(self):
# Asks user for their name
name = input('What is your name?')
# sends name to server
self.transport.write(name)
This will be speicifc to each client/connection, so you should only have one connectionMade method.
I have recently started developing a server-client chat protocol for learning purposes (later I would like to do more with this communication, but for now this suffices. Needless to say, I am still early into the learning phase of this portion of Python, but I have modified some examples to a server and a client that I found online. The communication works well from what I've seen so far, but I have to relaunch the client every time I want to send a message to the server.
Here is the code:
server:
from twisted.internet import reactor, protocol
from twisted.protocols import basic
class Echo(protocol.Protocol):
def dataReceived(self, data):
"As soon as any data is received, write it back."
self.transport.write(data)
class MyChat(basic.LineReceiver):
def connectionMade(self):
print "Got new client!"
self.factory.clients.append(self)
def connectionLost(self, reason):
print "Lost a client!"
self.factory.clients.remove(self)
def dataReceived(self, data):
print "received", repr(data)
for c in self.factory.clients:
c.message(data)
def message(self, message):
self.transport.write(message + '\n')
def main():
"""This runs the protocol on port 8000"""
factory = protocol.ServerFactory()
factory.protocol = MyChat
factory.clients = []
reactor.listenTCP(8000,factory)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
client:
from twisted.internet import reactor, protocol
# a client protocol
class EchoClient(protocol.Protocol):
"""Once connected, send a message, then print the result."""
def connectionMade(self):
self.transport.write("hello, world!")
def dataReceived(self, data):
"As soon as any data is received, write it back."
print "Server said:", data
self.transport.loseConnection()
def connectionLost(self, reason):
print "connection lost"
class EchoFactory(protocol.ClientFactory):
protocol = EchoClient
def clientConnectionFailed(self, connector, reason):
connector.connect()
print "Connection failed - goodbye!"
reactor.stop()
def clientConnectionLost(self, connector, reason):
connector.connect()
print "Connection lost - goodbye!"
reactor.stop()
# this connects the protocol to a server runing on port 8000
def main():
f = EchoFactory()
client = EchoClient()
reactor.connectTCP("localhost", 8000, f)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
What am I forgetting to add so that I can have multiple clients connected to the server and stay connected?
I looked here and here (the first one seems to be the same type of question) but I'm still confused as to how to fix this issue. Any suggestions are appreciated. Thanks!
I have a very simple client program:
class EchoClient(Int32StringReceiver):
def connectionMade(self):
print 'connection made.'
str = "<request><commands><dbtest /></commands></request>"
self.sendString(str)
print 'message sent'
def stringReceived(self, line):
print "receive:", line
self.transport.loseConnection()
class EchoClientFactory(ClientFactory):
def buildProtocol(self, addr):
return EchoClient()
def clientConnectionFailed(self, connector, reason):
print 'connection failed:', reason.getErrorMessage()
reactor.stop()
def clientConnectionLost(self, connector, reason):
print 'connection lost:', reason.getErrorMessage()
reactor.stop()
def main():
factory = EchoClientFactory()
reactor.connectTCP('localhost', 3604, factory)
reactor.run()
I connect to a Java service implemented in Apache CXF (and some proprietary company code).
It connects fine, sends the message, the service receives it and produces a response.
Sadly, this client does not wait for the server to produce its message, but disconnects right after the message is sent. So the output I get from the client is:
connection made.
message sent
connection lost: Connection was closed cleanly.
And of course the Java service throws an exception complaining about the connection being already closed.
What am I missing here?
EDIT: adding this line shows that the message is received, as it prints it correctly:
def dataReceived(self, data):
print(data)
self.transport.loseConnection()
So the real problem is that the stringReceived() function is not called. Maybe I have the wrong signature for this function?
I'm onto something here:
def lengthLimitExceeded(self, length):
print('length limit exceeded: {}'.format(length))
prints:
length limit exceeded: 2147483793
length limit exceeded: 2147483793
which is 0x80000091, so it seems that our propietary API is implementing the NString protocol in a strange way (maybe uses the MSB for something else).
I have this simple Twisted Client which connects to a Twisted server & queries an index.
If you see fn. connectionMade() in class SpellClient, the query is hard-coded. Did that for testing purposes. How would one pass this query from outside to this class?
The code -
from twisted.internet import reactor
from twisted.internet import protocol
# a client protocol
class SpellClient(protocol.Protocol):
"""Once connected, send a message, then print the result."""
def connectionMade(self):
query = 'abased'
self.transport.write(query)
def dataReceived(self, data):
"As soon as any data is received, write it back."
print "Server said:", data
self.transport.loseConnection()
def connectionLost(self, reason):
print "connection lost"
class SpellFactory(protocol.ClientFactory):
protocol = SpellClient
def clientConnectionFailed(self, connector, reason):
print "Connection failed - goodbye!"
reactor.stop()
def clientConnectionLost(self, connector, reason):
print "Connection lost - goodbye!"
reactor.stop()
# this connects the protocol to a server runing on port 8000
def main():
f = SpellFactory()
reactor.connectTCP("localhost", 8090, f)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
Protocols, like SpellClient, have access to their factory as self.factory.
...so there would be a number of ways to do this, but one way would be to create another method on SpellFactory, such as setQuery, and then access that from the client...
#...in SpellFactory:
def setQuery(self, query):
self.query = query
#...and in SpellClient:
def connectionMade(self):
self.transport.write(self.factory.query)
...so in main:
f = SpellFactory()
f.setQuery('some query')
...
...or you could just create an _init_ method for SpellFactory, and pass it in there.