I'm a bit new at Python and I am working on a robotics project. The short form of my question is that I am trying to find the best way (for my situation) to run multiple python programs at once.
A little bit of context, my robot is a platform for a service robot that is capable of following markers and paths using image algorithms and also receive commands from a remote computer. I want to have separate programs for the image processing, the driving, and so on, and then manage all of them through a main program. I know I can't use anything basic like functions or classes, because each of these processes must be looping continuously, and I don't want to combine all the code to run in a single while loop, because it runs very slowly and it is significantly harder to manage.
So, in short, how do I make two separate, looping programs "talk"? Like I want the imaging program to send information about what it sees to the driving and steering program, etc.
I did some research and I found some information on multithreading and API's and stuff like that, though I can't really tell which one is actually the thing I'm looking for.
To clarify, I just need to be pointed in the right direction. This doesn't seem like a very high-level thing, and I know there are definitely tutorials out there, I'm just really confused as to where to start as I am teaching myself this as I go.
After some sniffing around, I found that using IPC was a good solution. The process I used wasn't too difficult, I just made some very simple server and client classes and had them communicate over the Localhost IP. There's undoubtedly a better way to do this, but for a beginner like myself, it was a simple way to make two programs talk without modifying code too much. For those who are trying to do a similar thing as I did, here's the classes I made for myself. Fair warning, they're not exactly pristine or even very complex, but they got the job done.
Here's the class I made for the server:
import socket
from random import random
from time import sleep
class ServerObject:
def __init__(self,host_address,port):
self._host_address = host_address
self._s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self._s.bind((self._host_address,port))
def handshake(self):
print "Server Started. Awaiting Connection"
while True:
_data, _addr = self._s.recvfrom(1024)
if str(self._s.recvfrom(1024)[0]) == 'marco':
break
print 'marco recieved. sending polo...'
while True:
self._s.sendto('polo',_addr)
if str(self._s.recvfrom(1024)[0]) == 'confirm':
break
sleep(.5)
print 'connection verified'
self._addr = _addr
return True
def send(self,data):
self._s.sendto(str(data),self._addr)
def recieve(self,mode = 0):
_data, _addr = self._s.recvfrom(1024)
if mode == 0:
return str(_data)
if mode == 1:
return int(_data)
if mode == 2:
return float(_data)
if mode == 3:
return tuple(_data)
def change_port(self,port):
self._s.bind((self._host_address,port))
def close(self):
self._s.close()
print '_socket closed_'
if __name__ == '__main__':
host = '127.0.0.1'
talk = ServerObject(host,6003)
talk.handshake()
And here's the class I made for the client:
import socket
from time import sleep
class ClientObject:
def __init__(self,host_address,server_port,port = 0):
self._server = (host_address,server_port)
self._s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self._s.bind((host_address,port))
def handshake(self):
print ' sending marco'
self._s.sendto('marco',self._server)
sleep(.1)
self._s.sendto('marco',self._server)
while True:
if str(self._s.recvfrom(1024)[0]) == 'polo':
break
#self._s.sendto('marco',self._server)
#self._s.sendto('marco',self._server)
print ' connection verified'
self._s.sendto('confirm',self._server)
self._s.setblocking(0)
return True
def recieve(self,mode = 0):
_data, _addr = self._s.recvfrom(1024)
if mode == 0:
return str(_data)
if mode == 1:
return int(_data)
if mode == 2:
return float(_data)
if mode == 3:
return tuple(_data)
def send(self,data):
self._s.sendto(str(data),self._server)
def close(self):
self._s.close()
print '_socket closed_'
if __name__ == '__main__':
host = '127.0.0.1'
port = 0
talk = ClientObject(host,24603,port)
talk.handshake()
#while True:
#print talk.recieve()
Use the ServerObject class on the program that will primarily send data and the ClientObject class on the program that will primarily recieve data. These can be flipped around in many situations, but I found it's best to do it this way to take advantage of UDP. The client class has an optional port variable that is set to 0 by default. This is because for UDP the client needs another port to establish itself on. 0 means it will pick an available port, but if you specify one, it's possible to re-establish a connection if the client goes offline without needing to restart both programs.
Use the handshake first on both programs being sure to use the same IP and port (not referring to the last variable on the client) and then use the send and receive functions to pass data back and forth.
again, these aren't that good, in fact there's many problems that cab arise with using this method, but for a simple task, they got the job done. I set up the handshake to print verifications of what is happening, but if those get annoying, you can just remove those lines.
Hope this helps!
I think multiproccessing library could be a solution.
You will be able to run several processes in parallel when each process could perform it specific work, while sending data to each other.
You can check this example
This is generic directory walker, which have process that scans directory tree and passes the data to other process, which scans files in already discovered folders. All this done in parallel.
This is probably a little bit outside the scope of your project, but have you considered using ROS? It lets you run a bunch of different nodes (can be Python scripts) at the same time that communicate by publishing and subscribing to topics. They can be on the same system (i.e. one or more nodes on the robot) or different systems (i.e. one node on the robot, multiple nodes on the PC). ROS also has a lot of awesome built in tools and libraries that are specifically made for robotic systems such as visualization, mapping, odometry, etc. Here's a bit of starting info:
https://en.wikipedia.org/wiki/Robot_Operating_System
http://wiki.ros.org/ROS/StartGuide
It's usually used for much larger frameworks than you seem to be describing, and beware that it takes quite a bit of time (in my experience) to implement, but it is very easy to expand once its up and running. Like I said, it all depends on the scope of your project!
Good luck!
Related
I need to make a chat between two clients. But I don't know when a socket is closed or not, is there a way to check if it is?
Here is the part of the code that I need to fix:
def main():
"""Implements the conversation with server."""
# Open client socket, Transport layer: protocol TCP, Network layer: protocol IP
client_socket = socket.socket()
client_socket.connect((HOST_IP, PORT))
# start conversation with new client in parallel thread
name = input("enter your name ")
protocol.send_request(client_socket, name)
thread_for_responses = threading.Thread(target=get_responses,
args=(client_socket, ))
thread_for_responses.start()
while True:
# Get request from keyboard
client_request_str = input()
if client_request_str: # if client_request_str not empty string
# send request according to the protocol
protocol.send_request(client_socket, client_request_str)
# Get response from server
Instead of while True, I need to check if the socket is closed so it won't go into a loop where it will crush for using a closed socket.
Python programmers usually say it is easier to ask for forgiveness than for permission. By this they mean "handle the exception".
For example, you cannot divide by zero. Here are two ways you could deal with this fact:
def print_quotient(a, b):
if b == 0:
print("quotient is not a number")
else:
print("quotient is {}".format(a / b))
vs
def print_quotient(a, b):
try:
print("quotient is {}".format(a / b))
except ZeroDivisionError:
print("quotient is not a number")
These functions behave the same way so it doesn't make a lot of difference which approach you take. This is because b cannot change. This differs from your example where the socket can change. External factors influence its state and this changes the behavior of trying to use it (for example, to send bytes with it). In this case, exception handling is superior because it does not have to try to make sure nothing is going to go wrong, it just handles things when they go wrong. There is no case where the code thinks it has set everything up to work correctly and then it turns out it has missed something.
So, when you use socket operations, apply exception handling for any exceptions that might arise from those operations.
I have the task at hand to program all of the commands from a laser GUI to python so that we can use python instead of the GUI to control the laser. The problem: I don't really know where to start. I don't have any socket programming experience nor do I have knowledge of networking but I do know a bit of programming. To give you an idea of what I need to do, here is the PDF of what I have to program. PDF (p.s. if you don't have a Dropbox, you can just download the pdf)
That's the entire agenda. I have to define a class and use the commands there to make everything available in python.
My advisor started the program already but I am not sure what the code really means. I asked him where to go from here but he insists everything is covered in the pdf. The code is below.
I was hoping someone could point me in the right direction of what I should read/watch to understand how to code the rest. I read through some socket intros and TCP/IP intros and I understand the gist. The thing is, socket programming is a huge area and I don't know where to cut the wheat from the chaff. Note: the if statement at the end is already done, meaning there is nothing else to add (so says my supervisor). I only need to work on the class. The code is not really cemented in. If I find a/an better/easier way to work with the commands, then I could revamp the code. Any help is greatly appreciated.
Here is the code:
#!/usr/bin/env python
import PySide.QtNetwork as Network
import PySide.QtCore as Core
import configparser
class Spitlight():
"""The classe spitlight provides an interface so that we can the Innolas Spitlight Laser from python parameterize and operate.
"""
def __init__(self, *args, **kwargs):
"""constructor"""
pass
def ReadConfig(self, ConfigFile):
"""The parameters to operate the laser will come from the configurations file with the file ending *.ini"""
self.config = configparser.ConfigParser()
self.config.read(ConfigFile)
""" here the single parameters will be read and the parameters thoroughly checked. Later we will add parameter value limits so the laser will not function without being within the value limits.
Initial relevant options are:
flashbulb voltage, Repetition rate, pump duration, pockels cell control (Balance, Holdoff), delays
Futhermore the communication information is in the IP/Port of the laser server
return 0 """
def Start(self):
"""
Open socket with information from configuration
Send parameters to the laser and confirm that everything is in order e.g:
send SET_OSCILLATOR_AMPLITUDE with FLHighvoltage aus Config
"""
self.initSocket()
self.set_oscillator_amplitude()
def set_oscillator_amplitude(self):
self.tcpSocket.write("SET_OSCILLATOR_AMPLITUDE={}".format(self.Config['Laser parameter']['FLHighvoltage ']))
def set_oscillator_delay(self):
self.tcpSocket.write("SET_OSCILLATOR_DELAY={}".format(self.Config['Laser parameter']['FLDelay']))
def initSocket(self):
""" Socket initialize"""
self.tcpSocket = Network.QTcpSocket()
self.tcpSocket.disconnected.connect(self.connectSocket)
self.tcpSocket.readyRead.connect(self.readData)
self.connectSocket()
# regularly reconnect is stabilerregelmäßiger reconnect is more stable as leaving the socket the entire time open
self.reconnectTimer = Core.QTimer()
self.reconnectTimer.setInterval(120000) # 2 minutes
self.reconnectTimer.timeout.connect(self.reconnectSocket)
self.reconnectTimer.start()
return 0
#Core.Slot()
def connectSocket(self):
"""Socket connect"""
return self.tcpSocket.connectToHost(self.proxyAddress, self.proxyPort)
#Core.Slot()
def reconnectSocket(self):
"""Socket Status verify and again connect"""
""" Available states of tcpSocket.state() are:
QAbstractSocket.UnconnectedState The socket is not connected.
QAbstractSocket.HostLookupState The socket is performing a host name lookup.
QAbstractSocket.ConnectingState The socket has started establishing a connection.
QAbstractSocket.ConnectedState A connection is established.
QAbstractSocket.BoundState The socket is bound to an address and port (for servers).
QAbstractSocket.ClosingState The socket is about to close (data may still be waiting to be written).
QAbstractSocket.ListeningState For internal use only.
"""
if self.tcpSocket.state() in [ Network.QAbstractSocket.HostLookupState, Network.QAbstractSocket.ConnectingState, Network.QAbstractSocket.ListeningState ]:
return 0
if self.tcpSocket.state() == Network.QAbstractSocket.ConnectedState:
return self.tcpSocket.disconnectFromHost()
#Core.Slot()
def readData(self):
data = self.tcpSocket.readAll()
if str(data).startswith("ERROR="):
pass
elif str(data).startswith("WARNING="):
pass
elif:
pass
def FlOn(self):
"""send FLASHLAMP ON
verify with GET_LASER_STATE"""
return 0
"""testing framework:
laser start, parametrierize, flashbulb on, shutter off, shutter closed, flashbulb off, every of the functions gives a 0 when they were successful and a error message when not
"""
if __name__ == "__main__":
SpitligthControl = Spitlight()
SpitligthControl.ReadConfig('SpitlightConfig.ini')
SpitligthControl.Start()
SpitligthControl.FlOn()
SpitligthControl.StartEmission()
SpitligthControl.StopEmission()
SpitligthControl.FlOff()
I'm trying to connect to a TeamSpeak server using the QueryServer to make a bot. I've taken advice from this thread, however I still need help.
This is The TeamSpeak API that I'm using.
Before the edits, this was the summary of what actually happened in my script (1 connection):
It connects.
It checks for channel ID (and it's own client ID)
It joins the channel and starts reading everything
If someone says an specific command, it executes the command and then it disconnects.
How can I make it so it doesn't disconnect? How can I make the script stay in a "waiting" state so it can keep reading after the command is executed?
I am using Python 3.4.1.
I tried learning Threading but either I'm dumb or it doesn't work the way I thought it would. There's another "bug", once waiting for events, if I don't trigger anything with a command, it disconnects after 60 seconds.
#Librerias
import ts3
import threading
import datetime
from random import choice, sample
# Data needed #
USER = "thisisafakename"
PASS = "something"
HOST = "111.111.111.111"
PORT = 10011
SID = 1
class BotPrincipal:
def __init__(self, manejador=False):
self.ts3conn = ts3.query.TS3Connection(HOST, PORT)
self.ts3conn.login(client_login_name=USER, client_login_password=PASS)
self.ts3conn.use(sid=SID)
channelToJoin = Bot.GettingChannelID("TestingBot")
try: #Login with a client that is ok
self.ts3conn.clientupdate(client_nickname="The Reader Bot")
self.MyData = self.GettingMyData()
self.MoveUserToChannel(ChannelToJoin, Bot.MyData["client_id"])
self.suscribirEvento("textchannel", ChannelToJoin)
self.ts3conn.on_event = self.manejadorDeEventos
self.ts3conn.recv_in_thread()
except ts3.query.TS3QueryError: #Name already exists, 2nd client connect with this info
self.ts3conn.clientupdate(client_nickname="The Writer Bot")
self.MyData = self.GettingMyData()
self.MoveUserToChannel(ChannelToJoin, Bot.MyData["client_id"])
def __del__(self):
self.ts3conn.close()
def GettingMyData(self):
respuesta = self.ts3conn.whoami()
return respuesta.parsed[0]
def GettingChannelID(self, nombre):
respuesta = self.ts3conn.channelfind(pattern=ts3.escape.TS3Escape.unescape(nombre))
return respuesta.parsed[0]["cid"]
def MoveUserToChannel(self, idCanal, idUsuario, passCanal=None):
self.ts3conn.clientmove(cid=idCanal, clid=idUsuario, cpw=passCanal)
def suscribirEvento(self, tipoEvento, idCanal):
self.ts3conn.servernotifyregister(event=tipoEvento, id_=idCanal)
def SendTextToChannel(self, idCanal, mensajito="Error"):
self.ts3conn.sendtextmessage(targetmode=2, target=idCanal, msg=mensajito) #This works
print("test") #PROBLEM HERE This doesn't work. Why? the line above did work
def manejadorDeEventos(sender, event):
message = event.parsed[0]['msg']
if "test" in message: #This works
Bot.SendTextToChannel(ChannelToJoin, "This is a test") #This works
if __name__ == "__main__":
Bot = BotPrincipal()
threadprincipal = threading.Thread(target=Bot.__init__)
threadprincipal.start()
Prior to using 2 bots, I tested to launch the SendTextToChannel when it connects and it works perfectly, allowing me to do anything that I want after it sends the text to the channel. The bug that made entire python code stop only happens if it's triggered by the manejadorDeEventos
Edit 1 - Experimenting with threading.
I messed it up big time with threading, getting to the result where 2 clients connect at same time. Somehow i think 1 of them is reading the events and the other one is answering. The script doesn't close itself anymore and that's a win, but having a clone connection doesn't looks good.
Edit 2 - Updated code and actual state of the problem.
I managed to make the double connection works more or less "fine", but it disconnects if nothing happens in the room for 60 seconds. Tried using Threading.timer but I'm unable to make it works. The entire question code has been updated for it.
I would like an answer that helps me to do both reading from the channel and answering to it without the need of connect a second bot for it (like it's actually doing...) And I would give extra points if the answer also helps me to understand an easy way to make a query to the server each 50 seconds so it doesn't disconnects.
From looking at the source, recv_in_thread doesn't create a thread that loops around receiving messages until quit time, it creates a thread that receives a single message and then exits:
def recv_in_thread(self):
"""
Calls :meth:`recv` in a thread. This is useful,
if you used ``servernotifyregister`` and you expect to receive events.
"""
thread = threading.Thread(target=self.recv, args=(True,))
thread.start()
return None
That implies that you have to repeatedly call recv_in_thread, not just call it once.
I'm not sure exactly where to do so from reading the docs, but presumably it's at the end of whatever callback gets triggered by a received event; I think that's your manejadorDeEventos method? (Or maybe it's something related to the servernotifyregister method? I'm not sure what servernotifyregister is for and what on_event is for…)
That manejadorDeEventos brings up two side points:
You've declared manejadorDeEventos wrong. Every method has to take self as its first parameter. When you pass a bound method, like self.manejadorDeEventos, that bound self object is going to be passed as the first argument, before any arguments that the caller passes. (There are exceptions to this for classmethods and staticmethods, but those don't apply here.) Also, within that method, you should almost certainly be accessing self, not a global variable Bot that happens to be the same object as self.
If manejadorDeEventos is actually the callback for recv_in_thread, you've got a race condition here: if the first message comes in before your main threads finishes the on_event assignment, the recv_on_thread won't be able to call your event handler. (This is exactly the kind of bug that often shows up one time in a million, making it a huge pain to debug when you discover it months after deploying or publishing your code.) So, reverse those two lines.
One last thing: a brief glimpse at this library's code is a bit worrisome. It doesn't look like it's written by someone who really knows what they're doing. The method I copied above only has 3 lines of code, but it includes a useless return None and a leaked Thread that can never be joined, not to mention that the whole design of making you call this method (and spawn a new thread) after each event received is weird, and even more so given that it's not really explained. If this is the standard client library for a service you have to use, then you really don't have much choice in the matter, but if it's not, I'd consider looking for a different library.
Using two different computers, I have to implement sender and receiver algorithms to send and receive frames. I'm a strong programmer, but relatively new to network programming and python. The algorithms are below.
Sender-site algorithm:
while(true)
{
WaitForEvent();
if(Event(RequestToSend))
{
GetData();
MakeFrame();
SendFrame();
}
Receiver-site algorithm:
while(true)
{
WaitForEvent();
if(Event(ArrivalNotification))
{
ReceiveFrame();
ExtractData();
DeliverData();
}
I have to implement these algorithms on two separate computers, one as a sender and the other as a receiver. I have no idea where to start or look for examples. I've done some research with little luck. If someone can supply example code or a good article on implementing this, that would be lots of help.
I find myself using Python's Socket Server examples. This will get you going on the SendFrame(), ReceiveFrame(), and DeliverData() routines.
The MakeFrame() and ExtractData(), will vary widely based on how much data you're needing to send back and forth. I will try to dig up some good examples I have used in the past.
If you're looking for a 1 stop solution, I would suggest looking into Twisted. There is a definite learning curve to it, but it might be worth it to you. Note that if you're wanting to package the Python code into an exe using pyInstaller or py2exe, Twisted may give you trouble based on a number of threads I have read.
So after looking back through my notes, the framing aspect was a sore subject for me as I could not find any good examples to help. I instead wrote one from scratch and have (and still am) tweaking it.
As you read up on socket programming you will surely see that just because you send all the data (socket.sendall()) does not mean that you will receive it all after the first socket.recv(). This adds some complexity to the message framing question. Due to lack of examples on the web, below I have a stripped down version of what I am using right now in several processes.
Update
So after further testing the under heavy / bursting I moved away from the regex and process the stream character by character which has greatly improved its performance.
SendFrame(), ReceiveFrame(), ExtractData(), DeliverData() Examples:
MESSAGE_FRAME_START = '#'
MESSAGE_FRAME_END = '#'
def process_raw_socket_message_stream(raw_message_stream):
message_list = []
cmd = ''
last_footer_idx = message_string.rfind(MESSAGE_FRAME_END)
cmd_str_len = len(message_string)
byte_cnt = 0
while (byte_cnt <= last_footer_idx):
cmd_chr = message_string[byte_cnt]
cmd += cmd_chr
if cmd_chr == MESSAGE_FRAME_START:
cmd = MESSAGE_FRAME_START
elif cmd_chr == MESSAGE_FRAME_END:
message_list.append(cmd)
byte_cnt += 1
# Remove the parsed data
if last_footer_idx > 0:
message_string = message_string[last_footer_idx+1:]
return message_list, message_string
def add_message_frames(unframed_message):
return MESSAGE_FRAME_START + unframed_message + MESSAGE_FRAME_END
def remove_message_frames(framed_message):
clean_message = framed_message.lstrip(MESSAGE_FRAME_START)
clean_message = clean_message.rstrip(MESSAGE_FRAME_END)
return clean_message
def process_messsage(clean_message):
# Do what needs to be done
pass
def send_data(mysocket, payload):
framed_payload = add_message_frames(payload)
mysocket.sendall(framed_payload)
def receive_data(mysocket, byte_size=1024):
data = ''
while(1):
try: # Wait for data
data += mysocket.recv(byte_size)
if(data != '') and (data != None):
# Decode all messsages
message_list, remaining_data = process_raw_socket_message_stream(data)
# Process all of the messages
for messsage in message_list:
process_messsage(remove_message_frames(message))
# Store the remaining data
data = remaining_data
except:
print "Unexpected Error"
How can I create a non-http proxy with Twisted. Instead I would like to do it for the Terraria protocol which is made entirely of binary data. I see that they have a built-in proxy for HTTP connections, but this application needs to act more like an entry point which is forwarded to a set server (almost like a BNC on IRC).
I can't figure out how to read the data off of one connection and send it to the other connection.
I have already tried using a socket for this task, but the blocking recv and send methods do not work well as two connections need to be live at the same time.
There are several different ways to create proxies in Twisted. The basic technique is built on peering, by taking two different protocols, on two different ports, and somehow gluing them together so that they can exchange data with each other.
The simplest proxy is a port-forwarder. Twisted ships with a port-forwarder implementation, see http://twistedmatrix.com/documents/current/api/twisted.protocols.portforward.html for the (underdocumented) classes ProxyClient and ProxyServer, although the actual source at http://twistedmatrix.com/trac/browser/tags/releases/twisted-11.0.0/twisted/protocols/portforward.py might be more useful to read through. From there, we can see the basic technique of proxying in Twisted:
def dataReceived(self, data):
self.peer.transport.write(data)
When a proxying protocol receives data, it puts it out to the peer on the other side. That's it! Quite simple. Of course, you'll usually need some extra setup... Let's look at a couple of proxies I've written before.
This is a proxy for Darklight, a little peer-to-peer system I wrote. It is talking to a backend server, and it wants to only proxy data if the data doesn't match a predefined header. You can see that it uses ProxyClientFactory and endpoints (fancy ClientCreator, basically) to start proxying, and when it receives data, it has an opportunity to examine it before continuing, either to keep proxying or to switch protocols.
class DarkServerProtocol(Protocol):
"""
Shim protocol for servers.
"""
peer = None
buf = ""
def __init__(self, endpoint):
self.endpoint = endpoint
print "Protocol created..."
def challenge(self, challenge):
log.msg("Challenged: %s" % challenge)
# ...omitted for brevity...
return is_valid(challenge)
def connectionMade(self):
pcf = ProxyClientFactory()
pcf.setServer(self)
d = self.endpoint.connect(pcf)
d.addErrback(lambda failure: self.transport.loseConnection())
self.transport.pauseProducing()
def setPeer(self, peer):
# Our proxy passthrough has succeeded, so we will be seeing data
# coming through shortly.
log.msg("Established passthrough")
self.peer = peer
def dataReceived(self, data):
self.buf += data
# Examine whether we have received a challenge.
if self.challenge(self.buf):
# Excellent; change protocol.
p = DarkAMP()
p.factory = self.factory
self.transport.protocol = p
p.makeConnection(self.transport)
elif self.peer:
# Well, go ahead and send it through.
self.peer.transport.write(data)
This is a rather complex chunk of code which takes two StatefulProtocols and glues them together rather forcefully. This is from a VNC proxy (https://code.osuosl.org/projects/twisted-vncauthproxy to be precise), which needs its protocols to do a lot of pre-authentication stuff before they are ready to be joined. This kind of proxy is the worst case; for speed, you don't want to interact with the data going over the proxy, but you need to do some setup beforehand.
def start_proxying(result):
"""
Callback to start proxies.
"""
log.msg("Starting proxy")
client_result, server_result = result
success = True
client_success, client = client_result
server_success, server = server_result
if not client_success:
success = False
log.err("Had issues on client side...")
log.err(client)
if not server_success:
success = False
log.err("Had issues on server side...")
log.err(server)
if not success:
log.err("Had issues connecting, disconnecting both sides")
if not isinstance(client, Failure):
client.transport.loseConnection()
if not isinstance(server, Failure):
server.transport.loseConnection()
return
server.dataReceived = client.transport.write
client.dataReceived = server.transport.write
# Replay last bits of stuff in the pipe, if there's anything left.
data = server._sful_data[1].read()
if data:
client.transport.write(data)
data = client._sful_data[1].read()
if data:
server.transport.write(data)
server.transport.resumeProducing()
client.transport.resumeProducing()
log.msg("Proxying started!")
So, now that I've explained that...
I also wrote Bravo. As in, http://www.bravoserver.org/. So I know a bit about Minecraft, and thus about Terraria. You will probably want to parse the packets coming through your proxy on both sides, so your actual proxying might start out looking like this, but it will quickly evolve as you begin to understand the data you're proxying. Hopefully this is enough to get you started!