I have uploaded my python socket, (cloud service project), on azure ,and when ever I connected to Hercules client side socket ....after a message or two, connection closed by remote host... forcefully...?
Server Code
from twisted.internet.protocol import Factory, Protocol
from twisted.internet import reactor
import SocketServer
class IphoneChat(Protocol):
def connectionMade(self):
self.factory.clients.append(self)
print('clients are'), self.factory.clients
def connectionLost(self, reason):
self.factory.clients.remove(self)
def dataReceived(self, data):
msg = ""
msg = data.strip()
for c in self.factory.clients:
c.message(msg)
def message(self, message):
self.transport.write(message + '\n')
print ('Iphone Chat server startedd')
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
reactor.listenTCP(9073, factory)
reactor.run()
I tried to reproduce your issue on my environment, but failed. Base on my experience, we often pay attention to 3 points if we use socket in azure worker role.
Open input TCP port. If we open a port as listener port, we'd better to add this port into the endpoints setting.
Considered the worker role status, I suggest we can code logic into the while True loop function, as following,
while True:
reactor.listenTCP(65534, f)
print "server run"
reactor.run()
sleep(1.0)
According to the error message, I guess the reason is that azure load balancer will kill the idle connection in 240s. I recommend you can refer to this blog to configure your idleTimeoutInMinutes value.
Please try to check your project and configuration. Any further findings, please let me know.
Related
I am writing a TCP server to listen for TCP packets containing status information from remote machines. The remote machines keep the TCP connection alive once established.
Here are the salient parts of my code:
#!/usr/bin/python
from twisted.internet import reactor, protocol
class FactoryProcess(protocol.Protocol):
def dataReceived(self, data):
# Process received data
def send_data(self, message):
# Reply to message etc
self.transport.write(message)
factory = protocol.ServerFactory()
factory.protocol = FactoryProcess
reactor.listenTCP(8256,factory)
reactor.run()
The machines can connect and send their data, and I can send acknowledgements back in the send_data block.
So far, so good.
I cannot understand how to asynchronously send data to one of the devices from outside the Protocol code. Clearly, I need to somehow access an instance of the Factory class for the specific connection I wish to use but I cannot see how.
Keep safe and many thanks.
EDIT After #notorious.no provided a very helpful example, I changed my code to capture IP addresses and ports, also connection objects of connected devices:
from twisted.internet import endpoints, protocol, reactor
device_ips = []
device_ports = []
connections = []
class ChatProtocol(protocol.Protocol):
def connectionMade(self):
global device_ips, device_ports, connections
# Append client
self.factory.clientList.append(self)
print('client connected. Connection Count = ' + str(len(self.factory.clientList)))
connections.append(self)
ip, port = self.transport.client
device_ips.append(ip)
device_ports.append(port)
print('ips:' + str(device_ips) + ', ports:' + str(device_ports) + ', connections:' + str(connections))
def connectionLost(self, _):
# Remove client
self.factory.clientList.remove(self)
print('client lost. Connection Count = ' + str(len(self.factory.clientList)))
def dataReceived(self, data):
print('Data received:' + str(data))
# Send message to all connected clients
for client in self.factory.clientList:
if client == self:
continue
client.transport.write(data)
class ChatFactory(protocol.Factory):
protocol = ChatProtocol
clientList = []
def main():
epServer = endpoints.serverFromString(reactor, "tcp:8123")
epServer.listen(ChatFactory())
reactor.run()
main()
When I run this and then connect two test devices I get:
client connected. Connection Count = 1
ips:['redacted'], ports:[54182], connections:[<__main__.ChatProtocol instance at 0x7f5a835afcd0>]
client connected. Connection Count = 2
ips:['redacted', 'redacted'], ports:[54182, 57437], connections:[<__main__.ChatProtocol instance at 0x7f5a835afcd0>, <__main__.ChatProtocol instance at 0x7f5a835c2140>]
So now I have lists of connected device IPs and ports, and presumably I can use the connections objects to asynchronously send one a message when needed. Please could you advise how I can do this?
Keep safe...
Not really sure what you mean by "devices from outside the Protocol code" but I assume you mean accessing other clients that have connected to the same server (please comment if that's not the case). One thing you can do is have list of connected protocols in the factory object. The Factory.buildProtocol (by default, unless you overload it) will set the factory param in the protocol.
from twisted.internet import endpoints, protocol, reactor
class ChatProtocol(protocol.Protocol):
def connectionMade(self):
# Append client
self.factory.clientList.append(self)
print(len(self.factory.clientList))
def connectionLost(self, _):
# Remove client
self.factory.clientList.remove(self)
print(len(self.factory.clientList))
def dataReceived(self, data):
# Send message to all connected clients
for client in self.factory.clientList:
if client == self:
continue
client.transport.write(data)
class ChatFactory(protocol.Factory):
protocol = ChatProtocol
clientList = []
def main():
epServer = endpoints.serverFromString(reactor, "tcp:8256:interface=0.0.0.0")
epServer.listen(ChatFactory())
reactor.run()
main()
I may send messages to server from twisted client by calling connector.connect(). But clients will be made on different ports. Following code is demonstrated this case:
SERVER_HOST = 'localhost'
SERVER_PORT = '5000'
class EchoClient(protocol.Protocol):
def connectionMade(self):
self.transport.write("message")
self.transport.loseConnection()
class EchoFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
print('Connected.')
return EchoClient()
def clientConnectionLost(self, connector, reason):
print('Lost connection. Reason:', reason)
connector.connect()
def main():
reactor.connectTCP(SERVER_HOST, SERVER_PORT, EchoFactory())
reactor.run()
And my twisted server say me:
Packet received, client 127.0.0.1:41930, size: 7
Connection lost
Packet received, client 127.0.0.1:41931, size: 7
Connection lost
Packet received, client 127.0.0.1:41932, size: 7
Connection lost
Packet received, client 127.0.0.1:41933, size: 7
Clients has different ports - 41930, 41931, etc. How send messages from twisted client with single port?
You can use the bindAddress parameter in either connectTCP, clientFromString, TCP4ClientEndpoint, or TCP6ClientEndpoint. Using your example, your code would look like:
reactor.connectTCP(SERVER_HOST, SERVER_PORT, EchoFactory(), bindAddress=('127.0.0.1',9999))
I would advise you to avoid this if it's not absolutely necessary because the port may be in use by another process and will cause an exception. It's better for the OS to chose the ip:port for your app to bind to.
This is the code for my server.
import os
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
class IphoneChat(Protocol):
def connectionMade(self):
#self.transport.write("""connected""")
self.factory.clients.append(self)
print "client connected"
def connectionLost(self, reason):
self.factory.clients.remove(self)
print "client disconnected"
def dataReceived(self, data):
print "data is ", data
for c in self.factory.clients:
c.message(data)
def message(self, message):
self.transport.write(message + '\n')
factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
ON_HEROKU = os.environ.get('ON_HEROKU')
if ON_HEROKU:
# get the heroku port
port = int(os.environ.get('PORT', 17995))
else:
port = 3000
print "Iphone Chat server started on port: "
print port
reactor.listenTCP(port, factory)
reactor.run()
The code works perfectly locally, test it out for yourself. Just create a telnet communication via local host on port 3000 and you can seamlessly send and receive data.
However once I push this code to heroku and run the server, the server runs and prints out which port it is listening to, however when I try and create a connection to the server and send data, it just doesn't seem to pickup that a client is connected or send and receive data.
Can anyone resolve the issue?
I can't comment (not enough rep) but I think you aren't connecting to your app correctly. Usually to connect to heroku apps you connect to http://<appname>.herokuapp.com. I don't think you can directly connect to your app because of how heroku's routing system works.
See https://devcenter.heroku.com/articles/http-routing
I started working with Twisted Framework, I wrote a TCP server and I connect to it throw Telnet, it works fine. Now I want to manage connections and connected clients( sending data, cutting connections, etc etc) using an GUI like PyUI or GTK..
this is my code
import sys
import os
from twisted.internet import reactor, protocol
from twisted.python import log
class Server(protocol.Protocol):
def dataReceived(self, data):
log.msg ("data received: %s"%data)
self.transport.write("you sent: %s"%data)
def connectionMade(self):
self.client_host = self.transport.getPeer().host
self.client_port = self.transport.getPeer().port
if len(self.factory.clients) >= self.factory.clients_max:
log.msg("Too many connections !!")
self.transport.write("Too many connections, sorry\n")
self.transport.loseConnection()
else:
self.factory.clients.append((self.client_host,self.client_port))
log.msg("connection from %s:%s\n"%(self.client_host,str(self.client_port)))
self.transport.write(
"Welcome %s:%s\n" %(self.client_host,str(self.client_port)))
def connectionLost(self, reason):
log.msg('Connection lost from %s:%s. Reason: %s\n' % (self.client_host,str(self.client_port),reason.getErrorMessage()))
if (self.client_host,self.client_port) in self.factory.clients:
self.factory.clients.remove((self.client_host,self.client_port))
class MyFactory(protocol.ServerFactory):
protocol = Server
def __init__(self, clients_max=10):
self.clients_max = clients_max
self.clients = []
def main():
"""This runs the protocol on port 8000"""
log.startLogging(sys.stdout)
reactor.listenTCP(8000,MyFactory)
reactor.run()
if __name__ == '__main__':
main()
Thanks.
If you want to write a single Python program (process) that runs both your UI and your networking, you will first need to choose an appropriate Twisted reactor that integrates with the UI toolkit's event loop. See here.
Next, you might start with something simple, like have a button that when pressed will send a text message to all currently connected clients.
Another thing: what clients will connect? Browsers (also)? If so, you might contemplate about using WebSocket instead of raw TCP.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I can't get the Server and Client to communicate when they are both in different terminal windows. I can get them to both connect though not actually send their output to each others windows.I
Client:
from twisted.internet import reactor, stdio, protocol
from twisted.protocols import basic
class Echo(basic.LineReceiver):
def connectionMade(self):
print "Welcome to the Chat, you have now connected"
def lineReceived(self, line):
self.sendLine(line)
if line=="exit":
connectionLost()
def connectionLost(self):
self.transport.loseConnection()
class EchoClientFactory(protocol.ClientFactory):
protocol = Echo
factory = EchoClientFactory()
reactor.connectTCP("localhost", ...., factory)
reactor.run()
Server:
from twisted.internet import reactor, protocol, stdio
from twisted.protocols import basic
class Echo(basic.LineReceiver):
print "Welcome to Chat"
def connectionMade(self):
print "A new client has connected"
def lineReceived(self, line):
self.sendLine(line)
if line=="exit":
connectionLost()
def connectionLost(self):
self.transport.loseConnection()
class EchoServerFactory(protocol.ServerFactory):
protocol = Echo
factory = EchoServerFactory()
reactor.listenTCP(...., factory)
reactor.run()
It is vital that you always post the exact code that you are running - your Echo Server specifies .... as the port which raises a syntax error on execution. Posting the exact code will mean you get better responses faster.
Replacing the port with a number, 9999 say allows the server code to run. Now we can connect via telnet or netcat to test the server:
$ nc -c localhost 9999
hello
hello
Great! The server works fine. Note that it gives an error when you type "exit":
exceptions.NameError: global name 'loseConnection' is not defined
You should be calling self.transport.loseConnection() if you want to drop the connection manually. The connectionLost method you've defined is then called as an event to allow you to respond. You don't really need to define that method at this stage. Here is a modified version of your server code with the changes suggested:
from twisted.internet import reactor, protocol, stdio
from twisted.protocols import basic
class Echo(basic.LineReceiver):
print "Welcome to Chat"
def connectionMade(self):
print "A new client has connected"
def lineReceived(self, line):
print 'server received:', line
print 'server sent:', line, '\n'
self.sendLine(line)
if line=="exit":
self.transport.loseConnection()
class EchoServerFactory(protocol.ServerFactory):
protocol = Echo
factory = EchoServerFactory()
reactor.listenTCP(9999, factory)
reactor.run()
The client has the same problem with the port, changing to 9999 allows it to run. Your client connects, but then does not send any data. Here's a version that sends some text when it connects and echos text back to the server after a 2 second delay:
from twisted.internet import reactor, stdio, protocol
from twisted.protocols import basic
class Echo(basic.LineReceiver):
def connectionMade(self):
print "Welcome to the Chat, you have now connected"
# send some text when we connect
self.sendLine('hello')
def lineReceived(self, line):
print 'client received:', line
if len(line) > 10:
self.sendLine('exit')
else:
# send a response in 2 seconds
reactor.callLater(2, self.sendLine, '>' + line)
def connectionLost(self, reason):
reactor.stop()
class EchoClientFactory(protocol.ClientFactory):
protocol = Echo
factory = EchoClientFactory()
reactor.connectTCP("localhost", 9999, factory)
reactor.run()
This causes the original message to bounce back and forwards to the server, while the client prepends a > character each time. The client will then send "exit" when the message gets to a certain length, causing the connection to be dropped by the server. When the connection is dropped, the client can stop its reactor so that it exits.
Typing into the terminal window does not send data through your client to the server - use telnet or netcat for this purpose.