Solved

python - Why is my first crack at this datagram server a flop?

Posted on 2014-02-24
13
336 Views
Last Modified: 2014-03-16
Hi
Many of you know about my server woes.
I have Python ready to go on my machines now to do this properly, but in Python.

I can get simple stuff to work, but not the class infrastructure for my Server class.
What I have so far has "unexpected indents," and I can't see where. Does my program begin at the end ( like a main?)
    import threading

    class Server(Threading.Thread):
        def_init_(self, numclients):
            print('Server constructor: ')
            self.numClients=numclients
            print(numClients)
            print(' clients')

        def run(self):
            print('Server run()')


    serverThread=Server(2)

Open in new window

0
Comment
Question by:beavoid
  • 8
  • 5
13 Comments
 
LVL 16

Accepted Solution

by:
gelonida earned 500 total points
ID: 39883147
concerning the unexpected indents.

I think everything seems to be indented by a few characters.
just be sure, that the word
'import' of line 1 has no leading blanks and align the other lines accordingly




Apart from that:
you just created the thread but forgot to start it.

just add the line
serverThread.start()

Open in new window

at the end of your script
0
 

Author Comment

by:beavoid
ID: 39883472
Thanks

I made the changes, but now the error is

"Invalid syntax"

What is wrong?
How can Python be considered a cutting edge language, if it doesn't have a debugger?

My new code is :
import threading

class Server(Threading.Thread):
    def_init_(self, numclients):
        print('Server constructor: ')
        self.numClients=numclients
        print(numClients)
        print(' clients')
        
    def run(self):
        print('Server run()')

    


serverThread=Server(2)
srverThraad.start()

Open in new window

0
 
LVL 16

Assisted Solution

by:gelonida
gelonida earned 500 total points
ID: 39884300
you have still one space character before the import statement in line one

also line 4 is wrong

    def __init__(self, numclients):

Open in new window

so def, one whitespace and init with two leading and two trailing underscores.


please note also line 3.
Python is case sensitive, so it should be. 'threading' and not 'Threading'

Open in new window

line 7 should be either of two following lines
print(numclients) # refer to __init__'s parameter
print(self.numClients) # or use the attribute

Open in new window


By the way Python has a debugger. I never use it, but it has one.
and can be used from the command line.

If you use IDE's like for example Aptana studio, then you can run a debugger directly from the IDE.
However a debugger will not help you as long as you have syntax errors (in no prgramming language, that I know at least)

I personally just use an editor and a shell window, but an IDE can help a lot especially when learning a new language and aptana is supposed to ba quite good amongst the freely available IDEs
0
 

Author Comment

by:beavoid
ID: 39884654
Thanks, I've put the Shell error messages in this code block below
>>> ================================ RESTART ================================
>>> 
Server constructor: 
2
 clients
Traceback (most recent call last):
  File "/Users/jameshancock/Desktop/deep red wars/DRWpython/Server.py", line 17, in <module>
    serverThread.start()
AttributeError: 'Server' object has no attribute '_initialized'

Open in new window


must I specify that  "_initialized" attribute? Is that like a boolean?

start() is failing. It never enters the run area

Ideas?
Thanks

My present code is below   ( The space after 1: is not my space, it is a space that Expert Exchange puts into its text boxes after the line number)
import threading

class Server(threading.Thread):
    def __init__(self, numclients):
        print('Server constructor: ')
        self.numClients=numclients
        print(self.numClients)
        print(' clients')
        
    def run(self):
        print('Server run()')

    


serverThread=Server(2)
serverThread.start()

Open in new window

Again ;)
 ( The space after 1: is not my space, it is a space that Expert Exchange puts into its text boxes after the line number)
0
 
LVL 16

Assisted Solution

by:gelonida
gelonida earned 500 total points
ID: 39885024
Well I overlooked this.

In 99% of the cases you have to call the parent classes __init__() method when overriding the parent classes' __init__().

So you have two choices:
  either remove the entire declaration of  __init__() in your derived class, which is not possible in your case as you want to pass it the num_clients parameter.

or you call the parent's __init__() explicitely

import threading

class Server(threading.Thread):
    def __init__(self, numclients):
        threading.Thread.__init__(self) # call parent classes __init__ 
        print('Server constructor: ')
        self.numClients=numclients
        print(self.numClients)
        print(' clients')
        
    def run(self):
        print('Server run()')


serverThread=Server(2)
serverThread.start()

Open in new window

0
 

Author Comment

by:beavoid
ID: 39886460
Outstanding!

I also made an attempt at the Client, and again got syntax errors I don't know how to specify my server's IP address?

Can you see a problem? Are syntax errors a constant confounder in Python?
Thanks

import threading, socket

class Client(threading.Thread):
    def __init__(self, serveraddress, clientNumber):
        
        threading.Thread.__init__(self)  #  call parent class __init__

        serverAddress=serveraddress

        clientNumber=clientnumber

        host=serveraddress
        port=8081

    def run(self):
       print('Client constructor client # ', clientNumber)

       s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
       s.bind(("",0))
       sendto((  ?? , (host,port))  #how do I specify my server's address?




clientThread=Client(("192.168.1.113",port),0)
clientThread.start()
                         
                         
    


        


        


        

        

Open in new window

0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 16

Assisted Solution

by:gelonida
gelonida earned 500 total points
ID: 39891284
Syntax errors don't occur more often than in other languages, but starting with a new language does of course initially. Python is not too complicated to learn, but it has its pit falls especially when coming from another language.

You might think about using an IDE. With a correct installation syntax errors will already be highlighted during typing.

Please always send us the exact syntax error, that you encounter. (Makes it easier for us to help)
What is also important is whether you use python 2 or python 3. They are not always compatible and some code depends on the version. Occasionally it helps also to know under which OS you're running, though it matters less than the python version.


To give some general feedback:
lines 8 to 13 will do nothing useful.
they assign some values to local variables, which will be immediately auto destroyed when leaving the function __init__.

unlike C++/Java you have to prefix object members explicitely with 'self.'

so you had to could write:
    self.serverAddres s= serveraddress
    . . .


Alternatively you could, (but I really would recommend to NOT do this)  declare these variables as global variables.

for declaring for example the variable 'port' as global for the method __init__()
you had to insert following line between line 4 and 6
    global port

Open in new window




Even if you declared the variable port as global it would still not be known at line 25
as the __init__ functionhasn't been called so far.


Now concerning sockets"

It's quite some time, that I used sockets, but if I remember correctly

you should not have to bind a UDP client's socket.

your code should look
        data = 'hello' # or whatever byte string you want to send to
        s.sendto((  data , (self.host, self.port))

Open in new window

0
 

Author Comment

by:beavoid
ID: 39902161
Are global variables declared in the init? if not, how?
Thanks
0
 
LVL 16

Assisted Solution

by:gelonida
gelonida earned 500 total points
ID: 39902966
I would probably do something like:

import threading, socket


# variables outside of a classes or function's scope are global (to the module)
DEFAULT_PORT = 8081 # global variable


# next function is NOT needed it's just an example of how a function can 
# modify a  global variable.
# declare the var as global with the 'global' keyword and modify it from then on.
def change_default_port(port):
    global DEFAULT_PORT
    DEFAULT_PORT = port

class Client(threading.Thread):
    def __init__(self, server_address, client_number):
        threading.Thread.__init__(self)  #  call parent class __init__

        self.client_number=client_number
        self.host = server_address
        self.port = DEFAULT_PORT

    def run(self):
       print('Client constructor client # ', self.client_number)

       s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
       data = "whatever data you want to send"
       destination = (self.host, self.port)
       s.sendto( data , destination)  


clientThread=Client("192.168.1.113", 0)
clientThread.start()

Open in new window

0
 

Author Comment

by:beavoid
ID: 39903521
Excellent, thanks

A client first needs to send a MSG_HELO to the server.
How do I construct this bytearray, to be an array of 512 or 1024 bytes?
so, data = will be this bytearray, sent, and the server will analyze it in a setup loop.
Then, client will wait for a message from the server that all clients have joined, and it will exit the setup loop and begin the in-game loop. setup messages can be small, but in-game messages from client to server can also be small, but game-state messages from server to clients must be big, say - 4096 bytes? Or if I only send positional deltas and new unit arrivals, it can be smaller.
Should I be sending the updated game state / deltas at regular intervals, like  a clock? (Thread)

Thanks
0
 

Author Comment

by:beavoid
ID: 39914266
Outstanding, thanks

I have code working that
Server - a join loop that waits for HELO message from clients.
Client -  a start up message to the server is sent

I'd like to know if this is on the right track. - attached,
thanks
Have I left out anything that might be crucial in an RTS?

Note that the server will soon do an - "if all clients joined" - " do an in-game server-loop"
I havent considered structures that will house the game state.
The client will soon do its own "in-game" loop

I read that one professionally done network game is fully in Python, so I must shelve my hesitancy and apprehension in committing to Python for this project.
Aren't properly done network games - millions of lines of code?
Server.py
Client.py
0
 

Author Comment

by:beavoid
ID: 39915402
Included are my server and client below. No In Game Loop has been done, just the join.
Is this on the right track?

Please check them out. Thanks

Server:
import threading, socket

class Server(threading.Thread):

    MSG_JOIN = 0
    
    def intToBytes(self, n):
        print ("_________intToBytes___________")
        b = bytearray([0, 0, 0, 0])   # init
        b[3] = n & 0xFF
        n >>= 8
        b[2] = n & 0xFF
        n >>= 8
        b[1] = n & 0xFF
        n >>= 8
        b[0] = n & 0xFF    
    
        # Return the result or as bytearray
        return b

    
    
    def bytesToInt(self, b, offset):
        n = (b[offset+0]<<24) + (b[offset+1]<<16) + (b[offset+2]<<8) + b[offset+3]
        return n



    
    def __init__(self, numclients):
        threading.Thread.__init__(self) # call parent class's __init__ 
        print('Server constructor: ')
        self.expectedClientCount=numclients
        print(self.expectedClientCount, " clients expected")
        

    
        
    def run(self):
        
        print('Server run() . . . client join:')

        
        B = self.intToBytes(15976) #test convert and print
       
        print(B[0])
        print(" . ")
        print(B[1])
        print(" . ")
        print(B[2])
        print(" . ")
        print(B[3])
        print(" . ")
        print(self.bytesToInt(B,0))

        clientJoinMode=True
        
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        port = 1024
        bufferSize = 1024
        s.bind(("", port))
        joinedClientCount=0

        
        while clientJoinMode :   # CLIENT JOIN LOOP 

            
            print ('JOIN waiting on port: ', port, ' ',joinedClientCount,' /  ', self.expectedClientCount,' joined')   
            data, addr = s.recvfrom(bufferSize)
            msgType=data[0]

            
            cliNumBA = self.intToBytes(0) #create holder for client number bytes
            cliNumBA[0]=data[1]
            cliNumBA[1]=data[2]
            cliNumBA[2]=data[3]
            cliNumBA[3]=data[4]
            cliNum = self.bytesToInt(cliNumBA,0)
            #if msgType = 0:
            print ('joinloop JOIN from address ', addr, ': ', "client - ",cliNum)
            joinedClientCount+=1
          
        


serverThread=Server(3)
serverThread.start()

Open in new window


Client:

import threading, socket

class Client(threading.Thread):

    serverIP = "x.y.z.q"  # put the server's IP address here


    
    def intToBytes(self, n):
        print ("_________intToBytes___________")
        b = bytearray([0, 0, 0, 0])   # init
        b[3] = n & 0xFF
        n >>= 8
        b[2] = n & 0xFF
        n >>= 8
        b[1] = n & 0xFF
        n >>= 8
        b[0] = n & 0xFF    
    
        # Return the result or as bytearray  
        return b

    
    
    def bytesToInt(self, b, offset):
        n = (b[offset+0]<<24) + (b[offset+1]<<16) + (b[offset+2]<<8) + b[offset+3]
        return n



    
    def __init__(self, clientnumber):
        threading.Thread.__init__(self) # call parent class's __init__ 
        print(' Client number ', clientnumber, ' Constructor:' )
        self.clientNumber=clientnumber
        
        

    
        
    def run(self):

        print('Client run() . . . client # ', self.clientNumber)

        
        
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        
        bufferSize = 1024
        clientPort=1024+self.clientNumber
        serverPort = 1024
        sock.bind(("", clientPort))
        clientNumberBytesArray=self.intToBytes(self.clientNumber)
        
        sendBytes = bytearray(512) # create a byte[] holder for the JOIN message
        sendBytes[0]=0 #message type JOIN
        sendBytes[1]=clientNumberBytesArray[0]
        sendBytes[2]=clientNumberBytesArray[1]
        sendBytes[3]=clientNumberBytesArray[2]
        sendBytes[4]=clientNumberBytesArray[3]

        
         
        sock.sendto(sendBytes, (self.serverIP, serverPort))

        

        
       
          
        


clientThread0=Client(0)
clientThread0.start()

clientThread1=Client(1)
clientThread1.start()
clientThread2=Client(2)
clientThread2.start()

Open in new window

0
 

Author Comment

by:beavoid
ID: 39929453
Hi,

I've decided to try and do this in Java again, as I am more comfortable in Java. - for a possible porting to Python down the road. My other question determined that Java is a better choice for an RTS. - than a scripting language.
It is going well and I'd like to ask a Java RTS question about clock management.
Does anyone have an objection to me closing this question at this point?
I'm thinking I'll accept Gelonida's answers above.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

This article will show the steps for installing Python on Ubuntu Operating System. I have created a virtual machine with Ubuntu Operating system 8.10 and this installing process also works with upgraded version of Ubuntu OS. For installing Py…
Article by: Swadhin
Introduction of Lists in Python: There are six built-in types of sequences. Lists and tuples are the most common one. In this article we will see how to use Lists in python and how we can utilize it while doing our own program. In general we can al…
Learn the basics of strings in Python: declaration, operations, indices, and slicing. Strings are declared with quotations; for example: s = "string": Strings are immutable.: Strings may be concatenated or multiplied using the addition and multiplic…
Learn the basics of while and for loops in Python.  while loops are used for testing while, or until, a condition is met: The structure of a while loop is as follows:     while <condition>:         do something         repeate: The break statement m…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now