Ok, so I'm using python to learn socket programming. I'll move on to c in due time.
I thought that I would write a silly game to learn sockets with; feel free to use the source code yourself (.bmp files are 50x50 pixel images that I made in gimp). The server does not work at this point. (I'm pretty sure that it's hanging on the "c, addr = s.accept()")
I think a way to handle this is by using two threads. One thread to handle the communication server-side. And one thread to handle the game loop, also server side. The goal is to be able to play the game on both the server and the client. I've read that the 'twisted module' can handle multi-threading, I've never done multi-threading before, but it's supposed to be fairly non-trivial to do.
Secondly, I want to implement the communication between the server and the client in such a way that I don't overload the network and irritate my ISP (Internet Service Provider, for the less experienced developers). Is there a way that I can test the network and see how much information is actually getting passed between the server and the clients?
Right now, I only have small amount of information being passed between the client and server (information is only passed when players interact with the client or server by pushing a button). Is there a smarter message passing model that I should use instead?
GameServer.py
import pygame, sys, os
from pygame.locals import *
import socket
s = socket.socket()
host = socket.gethostname()
port = 6000
s.bind(('0.0.0.0',port))
s.listen(5)
#while True:
# c, addr = s.accept()
# print 'Got connection from', addr
# c.send('Hi blork, I am not rational either, but this works. So I am happy!')
# c.close()
window = pygame.display.set_mode((640,50))
pygame.display.set_caption("My Trivial Network Game: Get to the right side of the screen!")
class Ship():
xvel = 0
yvel = 0
x = 0
y = 0
image = pygame.image.load('ship.bmp')
def physics(self):
self.x += self.xvel
self.y += self.yvel
return self
class Bolt():
xvel = 0
yvel = 0
x = 640
y = 0
image = pygame.image.load('bolt.bmp')
def physics (self):
self.x += self.xvel
self.y += self.yvel
return self
def input(events):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
sys.exit()
# elif event.key == pygame.K_f:
# ship.xvel = 2
elif event.key == pygame.K_z:
bolt.xvel = -4
s.send('zap')
pygame.display.set_caption("Oh no! Jon's being a dork!!")
c.close()
if event.type == QUIT:
sys.exit(0)
#def MakeShip():
# pygame
ship = Ship()
bolt = Bolt()
box = pygame.Rect(0,0,640,50)
loopVal = 0
while True:
pygame.draw.rect(window,(0,0,0),box,0)
window.blit(ship.image, (ship.x,ship.y))
window.blit(bolt.image, (bolt.x,bolt.y))
if loopVal == 0:
loopVal += 1
c, addr = s.accept()
print "Now have connection from address: ", addr
input(pygame.event.get())
ship.physics()
bolt.physics()
pygame.display.update()
if (ship.x > 640):
pygame.display.set_caption("You win!")
GameClient.py
import pygame, sys, os
from pygame.locals import *
import socket
s = socket.socket()
host = socket.gethostname()
port = 6000
window = pygame.display.set_mode((640,50))
pygame.display.set_caption("My Small Network Game: Get to the right side of the screen!")
class Ship():
xvel = 0
yvel = 0
x = 0
y = 0
image = pygame.image.load('ship.bmp')
def physics(self):
self.x += self.xvel
self.y += self.yvel
return self
class Bolt():
xvel = 0
yvel = 0
x = 640
y = 0
image = pygame.image.load('bolt.bmp')
def physics (self):
self.x += self.xvel
self.y += self.yvel
return self
def input(events):
for event in events:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
sys.exit()
elif event.key == pygame.K_f:
ship.xvel = 2
# elif event.key == pygame.K_z:
# bolt.xvel = -4
# pygame.display.set_caption("Oh no! Jon's being a dork!!")
if event.type == QUIT:
sys.exit(0)
#def MakeShip():
# pygame
ship = Ship()
bolt = Bolt()
box = pygame.Rect(0,0,640,50)
s.connect((host, port))
reply = s.recv(1024)
print reply
while True:
pygame.draw.rect(window,(0,0,0),box,0)
window.blit(ship.image, (ship.x,ship.y))
window.blit(bolt.image, (bolt.x,bolt.y))
input(pygame.event.get())
ship.physics()
bolt.physics()
#reply = s.recv(1024)
print "He replied with zap!"
if reply == 'zap':
bolt.xvel = -4
pygame.display.set_caption("Oh no! Jon's being a dork!!")
pygame.display.update()
if (ship.x > 640):
pygame.display.set_caption("You win!")
-
1You are unlikely to cause problems with your ISP for a simple networked game. I wouldn't worry too much about measuring the bandwidth usage.Amber– Amber2013年08月20日 06:20:17 +00:00Commented Aug 20, 2013 at 6:20
-
That's a relief. Umm... for future reference how would I go about measuring bandwidth usage?user2522001– user25220012013年08月20日 06:28:54 +00:00Commented Aug 20, 2013 at 6:28
1 Answer 1
You are correct: s.accept() blocks until connection is established. The standard way is to use threads. This is the simpliest usage:
from threading import Thread
def server():
while True:
c, addr = s.accept()
print 'Got connection from', addr
c.send('Hi blork...')
c.close()
t = Thread(target=server)
t.start()
Note however that once the connection is established you should listen for incoming data from that socket. One of the ideas is to create a separate thread for each connection:
from threading import Thread
from socket import SHUT_RDWR
def client(sock):
while True:
data = sock.recv(2048)
if not data:
break
print data
try:
sock.shutdown(SHUT_RDWR)
sock.close()
except:
pass
def server():
while True:
c, addr = s.accept()
print 'Got connection from', addr
c.send('Hi blork...')
t = Thread(target=client, args=(c,))
t.start()
t = Thread(target=server)
t.start()
If you are talking about a game (with probably no more then 20 open connections at a time) this should be efficient enough. You don't have to bother with some sophisticated stuff like Twisted (which generally is supposed to be used as a high traffic server).
As for ISP: you should not worry about that at all. One way to test bandwidth is to create yet one more thread which will ping a client (say every second) and the client will pong back the server. Then you just measure the difference in time.
3 Comments
select.select() and only calls accept() if it is proved not to block.select (or any other asynchronous stuff) is not standard at all. It's difficult to work with it and it should be used only as a last resort (when efficiency matters) when everything else fails.