This is a read-only archive of the old Scratch 1.x Forums.
Try searching the current Scratch discussion forums.

#1 2010-10-12 17:28:46

kenrestivo
New Scratcher
Registered: 2010-10-12
Posts: 1

Network server for Scratch

Here is a simple server in Python that will connect a number of Scratch workstations together in a single network. They will all share broadcasts  with each other and variables. No extra software is required on the workstations, but you need to know their IP address and they need to Enable Sensors on the machines in order for the connection to work.  Some students used this to develop some network games. They discovered a hack to keep variables local: lists are not shared on the network, so if you want to keep a bunch of variables local, just create a list and access the variables as item X of the list.

If you find yourself continually connecting to the same machines,  you can create a conf file (see comments in the code) and pass that as an arg to the server when starting it.

Code:

#!/usr/bin/python

# Scratch server
# Copyright (C) 2010  ken restivo <ken aaattt  restivo.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.                                  
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


# based on ideas from
# Scratch Multiplayer Socket Server Demo
# http://scratchconnections.wik.is/Projects/Two-player_Network_Pong
#
# version 5.1.1  (Jul-31-2009)
# by Stefano Federici (on Scratch: "s_federici", email: federici.stefano@gmail.com)
#
# version 5.1  (Oct-16-2008)
# by Agnes Chang  (on Scratch: "kradeki", email: kradeki@gmail.com)
#


#
# To add machines to connect to at startup, create a conf file and pass it
# in as an argument to the program. 
# conf files have the format:
#  
# [machines]
# 127.0.0.1: 42001
# 192.167.80.5: 42001
#



from array import array
import socket
import time
import thread
import ConfigParser
import sys
import os


#####################
class ScratchServer:
        machines = [['127.0.0.1', 42001, None],
                    #['127.0.0.1', 42002, None]
                    ]
    log = False
        BUFSIZE = 4096
        config = None

        def __init__(self):
                return
        
        def start(self):    
                for i in xrange(len(self.machines)):
                        thread.start_new_thread(self.clientThread, (i,))
                print "threads spawned"
        
        
        def clientThread(self,i):
                data = None
                while 1:
                        s = None
                        print("connecting to %s on %s..." %(
                                        self.machines[i][0], 
                                        self.machines[i][1]))
                        while self.machines[i][2] == None:
                                try:
                                        s = socket.socket(socket.AF_INET, 
                                                          socket.SOCK_STREAM)
                                        s.connect((self.machines[i][0], 
                                                   self.machines[i][1]))
                                        self.machines[i][2] = s
                                except socket.error:
                                        time.sleep(30)
                        print("connected to %s on %s..." %(self.machines[i][0], 
                                                           self.machines[i][1]))
                        while 1:
                                try:
                                        data = s.recv(self.BUFSIZE)
                                except socket.error:
                                        self.machines[i][2] = None
                                if not data: break
                                if self.log == True:
                    print("received from %s (%s) >> %s" % (
                                                self.machines[i][0],
                                                self.machines[i][1], 
                                                data[4:]))
                                self.send_to_except(data, i)
                        s.close()
                        self.machines[i][2] = None
                        time.sleep(30)
                
        
        def build_command(self,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))
                return a.tostring() + cmd
        
        
        
        def send_to_except(self, fmt_cmd, mine):
                for i in xrange(len(self.machines)):
                        if self.machines[i][2] != None and mine != i:
                                try:
                                        self.machines[i][2].send(fmt_cmd)
                                except socket.error:
                                        self.machines[i][2].close()
                                        self.machines[i][2] = None
        
        
        
        def send_signal(self, broadcast):
                self.send_to_except(self.build_command('broadcast "%s"' % (
                                        str(broadcast))), 
                                  -1)
                if self.log == True:
            print '"' + broadcast + '" has been broadcasted.'
        
        
        def send_sensor(self, updateN, updateV):
                self.send_to_except(
                        self.build_command('sensor-update "%s" "%s"' % (
                                        str(updateN), str(updateV))), 
                        -1)
                print '"' + updateN + '" has been updated to "' + updateV + '"'
        
        
        def add_machine(self, addr, port):
                for i in self.machines:
                        if self.machines[0] == addr and self.machines[1] == port:
                                print "machine %s at %s is already added" % (
                                        addr, port)
                                return
                self.machines.append([addr, port, None])
                thread.start_new_thread(self.clientThread, 
                                        (len(self.machines)-1,))        
        
        
        def stop(self):
                print "closing connections..."
                for i in xrange(len(self.machines)):
                        if self.machines[i][2] != None:
                                self.machines[i][2].close()
                
        
        def parse_config(self, filename):
                try:
                        self.config = ConfigParser.ConfigParser()
                        self.config.read(filename)
                        for i in self.config.options('machines'):
                                self.add_machine(i, 
                                                 int(self.config.get(
                                                        'machines', i)))
                except   ConfigParser.MissingSectionHeaderError:
                        print "your conf file %s is not correctly written" % (
                                filename)
                        sys.exit(1)
        
         
##########################
        
class ScratchServerUI:
        server = None

        def __init__(self):
                self.server = ScratchServer()
                return
        
        def send_signal(self):
                broadcast = raw_input("Broadcast: ")
                if broadcast == None or broadcast == '':
                        return
                self.server.send_signal(broadcast)
        
        def send_sensor(self):
                updateN = raw_input("Sensor Name: ")
                if updateN == None or updateN == '':
                        return
                updateV = raw_input("Sensor Value: ")
                self.server.send_sensor(updateN, updateV)
        

        def add_machine(self):
                addr = raw_input("Hostname or IP address: ")
                if addr == None or addr == '':
                        return
                port = raw_input("Port: (default 42001 ")
                try:
                        p=int(port)
                except ValueError:
                        p=42001
                self.server.add_machine(addr, int(p))


        def list_machines(self):
                print "Machines and connections"
                print "---    Num  Address    Port     Status ---"
                for i in xrange(len(self.server.machines)):
                        m=self.server.machines[i]
                        if m[2] == None:
                                status = "connecting..."
                        else:
                                status  = "CONNECTED"
                        print("---    #%d. %s (%s) => %s" % (i, m[0], 
                                                             m[1], status))
        
        
        def menu(self):
                print """1) broadcast signal
2) set sensor variable
3) connect to a machine
4) list machines
5) toggle logging (currently %s)
0) quit""" % (self.server.log)
        
        
        def parse_config(self):
                try:
                        filename=sys.argv[1]
                except IndexError:
                        return
                if os.path.isfile(filename) == False:
                        print """file '%s' does not exist.
either start without a conf file, or supply an actual file""" % (
                                filename)
                        sys.exit()
                        
                print "using config file %s..." % (filename)
                self.server.parse_config(filename)


        def main_loop(self):
                while 1:
                        self.menu()
                        command = raw_input("Command (0-4): ")
                        if command == "1":
                                self.send_signal()
                        elif command == "2":
                                self.send_sensor()
                        elif command == "3":
                                self.add_machine()
                        elif command == "4":
                                self.list_machines()
                        elif command == "5":
                                self.server.log = not self.server.log
                        elif command == "0":
                                self.server.stop()
                                print "quitting..."
                                exit()
                        else:
                                print '"%s" is not a valid command.' % (command)



        def run(self):
                self.parse_config()
                self.server.start()
                self.main_loop()



#################
#  MAIN

ui = ScratchServerUI()
ui.run()

Offline

 

#2 2010-10-14 17:34:13

waveOSBeta
Scratcher
Registered: 2009-12-08
Posts: 1000+

Re: Network server for Scratch

Cool!


http://internetometer.com/image/10202.png]
New signature coming soon!  smile

Offline

 

#3 2010-10-26 15:11:05

johnnydean1
Scratcher
Registered: 2010-02-12
Posts: 1000+

Re: Network server for Scratch

*butp*


You can now reach me on Twitter @johnnydean1_

Offline

 

#4 2010-10-26 15:38:50

TheSuccessor
Scratcher
Registered: 2010-04-23
Posts: 1000+

Re: Network server for Scratch

johnnydean1 wrote:

*butp*

Bring up this post?


/* No comment */

Offline

 

#5 2010-10-26 15:56:01

johnnydean1
Scratcher
Registered: 2010-02-12
Posts: 1000+

Re: Network server for Scratch

their


You can now reach me on Twitter @johnnydean1_

Offline

 

#6 2010-10-28 17:59:18

stickdude123
Scratcher
Registered: 2010-05-31
Posts: 100+

Re: Network server for Scratch

this should be stickied!

<when green flag clicked>
<{ I HAVE NOT DONE THIS ONLINE BLOCK THING IN LONG TIME }>


http://internetometer.com/imagesmall/34259.png http://www.mediafire.com/convkey/418e/lkb7wmv2n2k73rz5g.jpg         http://blocks.scratchr.org/API.php?user=stickdude123&amp;action=onlineStatus&amp;type=square

Offline

 

#7 2010-12-15 20:46:21

runemoro
Scratcher
Registered: 2010-10-17
Posts: 4

Re: Network server for Scratch

I know python  smile  XD  :>

Offline

 

#8 2010-12-15 22:03:21

Magnie
Scratcher
Registered: 2007-12-12
Posts: 1000+

Re: Network server for Scratch

Interesting, just like Mesh. Maybe I'll try this out later.

Offline

 

#9 2010-12-15 22:10:58

BaronVonBlade
Scratcher
Registered: 2009-07-21
Posts: 500+

Re: Network server for Scratch

So this would be a server?
Once you get a host, would mesh games be able to support more than 2 players on the server?


http://img820.imageshack.us/img820/6055/imagevxqx.jpghttp://img820.imageshack.us/img820/6055/imagevxqx.jpg

Offline

 

#10 2011-05-24 18:14:15

compuman
Scratcher
Registered: 2009-09-23
Posts: 3

Re: Network server for Scratch

I am one of his students who created a networked game.

Offline

 

Board footer