Triggering a TCP client after starting reactor.run ()

I am trying to make a p2p application to send only text messages. The way I do this is that the server is running as long as the application is running, and the client that connects to another node server to send messages. For testing purposes, I do this with localhost, that is, I am talking to myself.

So, I have the following:

from twisted.internet import reactor from mylib import MessageSFactory def send_message(message): reactor.connectTCP("localhost", 8080, MessageCFactory(message)) reactor.listenTCP(8080, MessageSFactory()) reactor.connectTCP("localhost", 8080, MessageCFactory("this message gets received")) reactor.run() send_message("this message doesn't") 

However, the problem is calling send_message (last line) after reactor.run does not seem to have an effect.

The problem is that I need to start the tcp client part ( connectTCP ) only when the user fills in the message and sends it. Therefore, I am trying to do this by calling send_message . So how can I fix the above code to make this work?

From what I have read so far, using LoopingCall would be the right way, but I have to store the new messages that the client enters into the variable and constantly check this variable for the new message, and not run send_message This will delay the user input and function callback, whether this is my best option?

Is there any other way to do this in this scenario? Or am I missing an understanding of some important part of twisted architecture?

EDIT: as requested, here is a GUI code that receives a message from the client:

 from Tkinter import * def send_message(): print("message: %s" % (e1.get())) master = Tk() Label(master, text="Message").grid(row=0) e1 = Entry(master) e1.grid(row=0, column=1) Button(master, text='Send', command=send_message).grid(row=3, column=1, sticky=W, pady=4) mainloop() 

thanks

+6
source share
1 answer

The most important problem is that both Tkinter and Twisted solve similar problems in a similar way, namely they respond asynchronously to external events. The fact that Tkinter is focused on gui and Twitsted events on network events is extremely important.

The specific thing that they do is that they have a β€œmain loop” structure, a kind of point from where there is no return from which you lose control. In case of twisting, usually reactor.run() , and in tkinter it will be Tkinter.mainloop() . Both will not return until the program exits.

Fortunately, you can get Twisted up to manage the tk event loop for you! At the beginning of your program, you should add:

 from Tkinter import Tk from twisted.internet import tksupport root_window = Tk() tksupport.install(root_window) 

then, once you have created your gui as usual, you should not call Tkinter.mainloop() , use:

 from twisted.internet import reactor root_window.protocol("WM_DELETE_WINDOW", reactor.stop) reactor.run() 

The odd bit with Tk.protocol() is optional, but will get rid of some terrible exceptions by shutting down the reactor normally when gui tries to exit.


In case this is not enough, here is some real working code! First a really simple server

 from twisted.internet.protocol import Protocol, Factory from twisted.internet import reactor class Echo(Protocol): def dataReceived(self, data): print 'recieved:', data def connectionLost(self, reason): print 'connection closed', reason f = Factory() f.protocol = Echo reactor.listenTCP(8080, f) reactor.run() 

and client with gui and network activity:

 from Tkinter import * from twisted.internet import tksupport, reactor master = Tk() tksupport.install(master) def send_message(): message = e1.get() reactor.connectTCP("localhost", 8080, MessageCFactory(message)) print("message: %s" % (message)) Label(master, text="Message").grid(row=0) e1 = Entry(master) e1.grid(row=0, column=1) Button(master, text='Send', command=send_message).grid(row=3, column=1, sticky=W, pady=4) from twisted.internet.protocol import ClientFactory, Protocol from twisted.internet import reactor class MessageCProto(Protocol): def connectionMade(self): self.transport.write(self.factory.message) self.transport.loseConnection() class MessageCFactory(ClientFactory): protocol = MessageCProto def __init__(self, message): self.message = message master.protocol("WM_DELETE_WINDOW", reactor.stop) reactor.run() 
+2
source

Source: https://habr.com/ru/post/973276/


All Articles