I created this repo recently and thought some of you might find it useful for your projects. There are a lot of ways to create a stand-alone tcp socket server in python and a shitload of examples out there so it can be a bit difficult to figure out which is the best one to use or start from.
I use this particular example pretty often when we need to communicate to TD from a Flask app or really any python app/code that would be risky (or impossible) to run directly from TD.
If you were to send a message to it from TD you could use the TCP DAT and do something like this from a Text DAT:
from datetime import datetime
import json
msg = {
'cmd': 'test',
'data': [str(datetime.now())],
}
msg = json.dumps(msg)
op('tcpip1').send(msg)
And then parse the incoming message in the callback script for the TCP DAT like so:
import json
def onReceive(dat, rowIndex, message, bytes, peer):
myjson = json.loads(message)
cmd = myjson['cmd']
data = myjson['data']
print(cmd, data)
return
One interesting thing I have noticed is that TD tends to add an extra byte on the end of the message (0x00). I’m a little unclear about why this would happen but I added this line in the server to help deal with that issue:
data = loads(data.rstrip('\0'))
This example could be enhanced with the addition of a user provided callback function for the received client messages but I decided that it would be better not to overly complicate things. Later on I may add a different version for that.
Enjoy!
1 Like
Thanks Matthewwatcher, simple and easy to read code.
I d be interesting in seeing the user provided callback functions example if that’s possible. Wonder a few time how to structure those callbacks.
Cheers.
@oliviano something like this
from datetime import datetime
from json import loads, dumps
from pprint import pprint
import socket
from threading import Thread
class ThreadedServer(Thread):
def __init__(self, host, port, timeout=60, callback=None, debug=False):
self.host = host
self.port = port
self.timeout = timeout
self.callback = callback
self.debug = debug
Thread.__init__(self)
# run by the Thread object
def run(self):
if self.debug:
print(datetime.now())
print('SERVER Starting...', '\n')
self.listen()
def listen(self):
# create an instance of socket
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# bind the socket to its host and port
self.sock.bind((self.host, self.port))
if self.debug:
print(datetime.now())
print('SERVER Socket Bound', self.host, self.port, '\n')
# start listening for a client
self.sock.listen(5)
if self.debug:
print(datetime.now())
print('SERVER Listening...', '\n')
while True:
# get the client object and address
client, address = self.sock.accept()
# set a timeout
client.settimeout(self.timeout)
if self.debug:
print(datetime.now())
print('CLIENT Connected:', client, '\n')
# start a thread to listen to the client
Thread(
target=self.listenToClient,
args=(client, address, self.callback)
).start()
# send the client a connection message
# res = {
# 'cmd': 'connected',
# }
# response = dumps(res)
# client.send(response.encode('utf-8'))
def listenToClient(self, client, address, callback):
# set a buffer size ( could be 2048 or 4096 / power of 2 )
size = 1024
while True:
try:
# try to receive data from the client
data = client.recv(size).decode('utf-8')
if data:
data = loads(data.rstrip('\0'))
if self.debug:
print(datetime.now())
print('CLIENT Data Received', client)
print('Data:')
pprint(data, width=1)
print('\n')
if callback is not None:
callback(client, address, data)
else:
raise error('Client disconnected')
except:
if self.debug:
print(datetime.now())
print('CLIENT Disconnected:', client, '\n')
client.close()
return False
def some_callback(client, address, data):
print('data received', data)
# send a response back to the client
res = {
'cmd': data['cmd'],
'data': data['data']
}
response = dumps(res)
client.send(response.encode('utf-8'))
if __name__ == "__main__":
ThreadedServer('127.0.0.1', 8008, timeout=86400, callback=some_callback, debug=True).start()
1 Like