So I'm going back and looking at the scratch-send.py code for Scratch's Remote Connections:
from array import array
import socket
import time
HOST = '127.0.0.1'
PORT = 42001
def sendScratchCommand(cmd):
n = len(cmd)
a = array('c')
a.append(chr((n >> 24) & 0xFF))
a.append(chr((n >> 16) & 0xFF))
a.append(chr((n >> 8) & 0xFF))
a.append(chr(n & 0xFF))
scratchSock.send(a.tostring() + cmd)
print a.tostring() + cmd # Was used for debugging purposes.
print("connecting...")
scratchSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
scratchSock.connect((HOST, PORT))
print("connected")
for i in xrange(10):
sendScratchCommand('ensor-update note ' + str(60 + (2 * i)) + ' beats 0.4')
sendScratchCommand('broadcast "beat"')
print("beat!")
time.sleep(0.5)
print("closing socket...")
scratchSock.close()
print("done")And I noticed/remembered the array:
def sendScratchCommand(cmd):
n = len(cmd)
a = array('c')
a.append(chr((n >> 24) & 0xFF))
a.append(chr((n >> 16) & 0xFF))
a.append(chr((n >> 8) & 0xFF))
a.append(chr(n & 0xFF))
scratchSock.send(a.tostring() + cmd)
print a.tostring() + cmd # Was used for debugging purposes.And I wonder what it necessarily does and how to "decode" it or Remove it from the string to allow me to use what data is received from Scratch.
Any idea on how to do that?
Offline
This is from the Scratch Extensions Protocol:
Each message consists of a four-byte size field, most-significant byte first, followed by the message itself:
<size: 4 bytes><msg: size bytes>
So the array you're talking about just pushes the length of the command into a four-byte array (one byte at a time) and then sends that off with the command. The protocol should also explain how to understand the messages that Scratch sends back. To receive these messages you can append this to your code:
while True:
update = scratchSock.recv(1024)
if not update: break
parse_data(update)
def parse_data(update):
# Parse the update...
Offline
Thank you Fullmoon.
The protocol doesn't tell me how to parse the data though. But I guess I could remove the first 4 or 8 characters of a string then do whatever I want with it. Any other ideas or ways to parse the data?
Offline
Magnie wrote:
Thank you Fullmoon.
The protocol doesn't tell me how to parse the data though. But I guess I could remove the first 4 or 8 characters of a string then do whatever I want with it. Any other ideas or ways to parse the data?
I wrote an Actionscript 3 class a while ago called ScratchSocket that has utility functions for parsing Scratch data. Here's the source, but it won't compile because I didn't include the helper classes. The important bit is in the evaluate() function:
private function evaluate(s:String):void {
var broadcast_pattern:RegExp=/broadcast\s\"(.*)"/;
var sensor_pattern:RegExp=/sensor-update\s\"(.*?)\"\s\"(.*?)\"/;
var sensor_num_pattern:RegExp=/sensor-update\s\"(.*?)\"\s([-|\d|.]+)/;
var result:Object;
//Check to see whether the input is a broadcast, a sensor-update, or a request
result=broadcast_pattern.exec(s);
if (result != null) {
dispatchEvent(new ScratchBroadcastEvent(result[1]));
}
result=sensor_pattern.exec(s);
if (result != null) {
dispatchEvent(new ScratchSensorUpdateEvent(result[1],result[2]));
} else {
}
result=sensor_num_pattern.exec(s)
if(result != null){
dispatchEvent(new ScratchSensorUpdateEvent(result[1],result[2]));
}
}It uses regular expressions to parse the data. I'm not that great at Python but let me see if I can whip up an equivalent for you.

Offline
Here we are, Python equivalents:
ScratchClientModified has a function called parseData that parses the input from Scratch and then calls either broadcastIn() or sensorUpdateIn().
ScratchSocket contains a Python class that wraps up this functionality along with helper functions for broadcasting and updating to scratch. Note that if you want to add more interaction to this class, it'll have to happen in the broadcastIn() or sensorUpdateIn() functions since the ScratchSocket constructor contains an infinite loop.
Hope this helps!
(School was cancelled today so that's why I'm able to write random Python classes in the middle of the day. Time to go take advantage of all the snow we're getting!
)

Offline
Ah, thank you Fullmoon! My project is to create a Python Mirror, so it connects to Scratch and a Server. I'm trying to make this because I really never liked how Mesh works and I'm trying to create an alternative to it. I'll make another topic once I'm done working on it. Thank you again.
Offline
Magnie wrote:
Ah, thank you Fullmoon! My project is to create a Python Mirror, so it connects to Scratch and a Server. I'm trying to make this because I really never liked how Mesh works and I'm trying to create an alternative to it. I'll make another topic once I'm done working on it. Thank you again.
![]()
That sounds really cool! Let me know if I can be of any more help.

Offline
Actually, there is something. How does the "group(1),group(2)" work? And how would I be able to turn the
self.parsed == 'broadcast start'
to
self.parsed.group(0) == 'broadcast' and self.parsed.group(1) == 'start'
?
class Client(threading.Thread):
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
def run(self):
print self.address,'has connected.'
running = 1
while running:
data = self.client.recv(self.size)
if data:
exec parseData(data)
if self.parsed == 'broadcast start':
exe = """sendScratchCommand('sensor-update "x" "0"')
sendScratchCommand('sensor-update "y" "0"')
"""
self.client.send(exe)
else:
self.client.close()
running = 0into:
class Client(threading.Thread):
def __init__(self,(client,address)):
threading.Thread.__init__(self)
self.client = client
self.address = address
self.size = 1024
def run(self):
print self.address,'has connected.'
running = 1
while running:
data = self.client.recv(self.size)
if data:
exec parseData(data)
if self.parsed.group(0) == 'broadcast' and self.parsed.group(1) == 'start':
exe = """sendScratchCommand('sensor-update "x" "0"')
sendScratchCommand('sensor-update "y" "0"')
"""
self.client.send(exe)
else:
self.client.close()
running = 0?
It probably isn't important, but it could come useful in the future. Like:
if self.parsed.group(0) == 'broadcast':
if self.parsed.group(1) == 'start':
exe = 'print "Something"'or
self.cmd == self.parsed.group(0)
self.value == self.parsed.group(1)
if self.cmd == 'broadcast':
if self.value == 'start':
exe = 'print "Something"'Offline
I don't know how familiar you are with regexes, but the re.search() function takes a regular expression and tests it against a string. This returns an object with a group() method. Every time you see parentheses in the regular expression, Python takes what it finds in that part of the regex and adds it to the group -- so the parentheses are basically a way of extracting the unknown bits from the data (in this case, the broadcast name and sensor values) from the known parts (the structure of the command, including "broadcast" and "sensor-update"). You're using some self.parsed variable, but you really don't need to. In the class I wrote, all updates get sent to the sensorUpdateIn and broadcastIn methods, depending on their type. So to do more with the updates than just print them out, modify those methods. For example:
def broadcastIn(self,broadcast):
if broadcast == "something":
#Something significant has been broadcastI do hope I understand what you're getting at, but to me it looks like this problem is already solved!
Let me know.

Offline
That makes sense. But what I have is the definitions on there own, I'm just hoping they won't clash with other Clients connecting to the server. So when two players press the up arrow key, sending a broadcast and the Python Server takes both then both call up the same definition. I guess I could fix that by moving the definition into the same Client Class. Oh well, I'll figure it out. Thanks for your help Fullmoon.
Offline