So I did the following (This app is a client and a server at the same time):
class WebCheckerCommandProtocol(recvline.HistoricRecvLine):
def connectionMade(self):
self.sendLine("checker console. Type 'help' for help.")
def lineReceived(self, line):
...
def connectionLost(self, reason):
# stop the reactor, only because this is meant to be run in Stdio.
reactor.stop()
def do_listservers(self):
"Cmd to Query all available Servers - Takes no arguments"
conn = httplib.HTTPConnection(ip+":"+port)
conn.request(.....)
response = conn.getresponse()
print response.status, response.reason
data = response.read()
def do_sessions(self):
conn = httplib.HTTPConnection(ip+":"+port)
conn.request(.....)
def do_logUser(self, name):
conn = httplib.HTTPConnection(ip+":"+port)
conn.request(.....)
class SimpleServer(LineReceiver):
def connectionMade(self):
print 'Connection from: ', self.transport.client
def connectionLost(self, reason):
print self.transport.client, 'Disconnected'
def dataReceived(self, line):
"""Here the XML Parser"""
print line
if __name__ == "__main__":
factory = Factory()
factory.protocol = SimpleServer
runWithProtocol(WebCheckerCommandProtocol)
reactor.listenTCP(1234, factory)
reactor.run()
When I run it I see the command line, but nothing else works. I can write commands but they don't seem to work. I see nothing at the console.
What am I doing wrong?
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')
When I try and run this (see code below) I get the "connection made" response from the server and the command prompt to write an input. However when I try and enter the input it just hangs and the server doesn't seem to receive the message. Anyone know why this is?
Thanks, please say if this isn't clear enough
Here is my chat server:
from twisted.protocols import basic
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 lineReceived(self, line):
print "received", repr(line)
for c in self.factory.clients:
c.message(line)
def message(self, message):
self.transport.write(message + '\n')
from twisted.internet import reactor, protocol
from twisted.application import service, internet
factory = protocol.ServerFactory()
factory.protocol = MyChat
factory.clients = []
reactor.listenTCP(8004, factory)
reactor.run()
and here is my client:
from twisted.internet import reactor, protocol
# a client protocol
class EchoClient(protocol.Protocol):
def sendData(self):
data = raw_input("> ")
if data:
print "sending %s...." % data
self.transport.write(data)
else:
self.transport.loseConnection()
def connectionMade(self):
self.sendData()
def dataReceived(self, data):
print data
self.sendData()
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 runing on port 8000
def main():
f = EchoFactory()
reactor.connectTCP("localhost", 8004, f)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
You made a mistake in the client. Basically, server expects to receive lines, meaning data terminated by newline. However, client sends data without newline character at the end.
So, to fix client, just add \r\n to the data:
self.transport.write(data + "\r\n")
Here is client protocol:
class EchoClient(protocol.Protocol):
def sendData(self):
data = raw_input("> ")
if data:
print "sending %s...." % data
self.transport.write(data + "\r\n")
else:
self.transport.loseConnection()
def connectionMade(self):
self.sendData()
def dataReceived(self, data):
print data
self.sendData()
def connectionLost(self, reason):
print "connection lost"
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 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.
What I'm trying to do is fairly simple: send a file from client to server. First, the client sends information about the file - the size of it that is. Then it sends the actual file.
This is what I've done so far:
Server.py
from twisted.internet import reactor, protocol
from twisted.protocols.basic import LineReceiver
import pickle
import sys
class Echo(LineReceiver):
def connectionMade(self):
self.factory.clients.append(self)
self.setRawMode()
def connectionLost(self, reason):
self.factory.clients.remove(self)
def lineReceived(self, data):
print "line", data
def rawDataReceived(self, data):
try:
obj = pickle.loads(data)
print obj
except:
print data
#self.transport.write("wa2")
def main():
"""This runs the protocol on port 8000"""
factory = protocol.ServerFactory()
factory.protocol = Echo
factory.clients = []
reactor.listenTCP(8000,factory)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
Client.py
import pickle
from twisted.internet import reactor, protocol
import time
import os.path
from twisted.protocols.basic import LineReceiver
class EchoClient(LineReceiver):
def connectionMade(self):
file = "some file that is a couple of megs"
filesize = os.path.getsize(file)
self.sendLine(pickle.dumps({"size":filesize}))
f = open(file, "rb")
contents = f.read()
print contents[:20]
self.sendLine(contents[:20])
f.close()
# self.sendLine("hej")
# self.sendLine("wa")
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 runing on port 8000
def main():
f = EchoFactory()
reactor.connectTCP("localhost", 8000, f)
reactor.run()
# this only runs if the module was *not* imported
if __name__ == '__main__':
main()
The server will only output the deserialized object:
{'size': 183574528L}
How come? What happend to the 20 chars from the file I wanted to send?
If use the "hej" and "wa" sends instead, I will get them both (in the same message, not twice).
Somebody?
You've set your server to raw mode with setRawMode(), so the callback rawDataReceived is being called with the incoming data (not lineReceived). If you print the data you receive in rawDataReceived, you see everything including the file content, but as you call pickle to deserialize the data, it's being ignored.
Either you change the way you send data to the server (I would suggest the netstring format) or you pass the content inside the pickle serialized object, and do this in one call.
self.sendLine(pickle.dumps({"size":filesize, 'content': contents[:20]}))