-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathserver.py
167 lines (136 loc) · 4.51 KB
/
server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# Server protocol for battleship
# A quick note on technical limitations: for the sake of this project's simplicity and my own
# sanity, I make a pretty risky assumption about my sockets: that every single communication
# will successfully send all 1024 bytes in one go.
# Naturally, when you are in a networking environment there are hundreds of factors that may
# affect the fidelity of the connection and this represents a bit of a risk. However, in our
# case we appear to come well within the 1024 byte limit for a single transmit.
# our data array (the only significant thing we are sending) comes in at 192 bytes, empty:
# >>> sys.getsizeof([[0 for i in range(10)] for j in range(10)])
# 192
# of course, pickling it for serialization introduces significant size overhead:
# >>> import pickle
# >>> sys.getsizeof(pickle.dumps([[0 for i in range(10)] for j in range(10)]))
# 507
# but even with a fully populated array, we seem to be just fine:
# >>> sys.getsizeof(pickle.dumps([[256 for i in range(10)] for j in range(10)]))
# 707
# of course, staying under the size requirement isn't a guarantee, but it certainly makes me
# feel better. There is a possibility of transmission failures due to other network issues, but
# the code should mostly compensate for these by virtue of constantly updating - if the data array
# is transmitted mashed in one pass, it should be corrected on the next pass. this is further
# enforced by the fact that our server is authoritative and will contain the One True State of our
# game board, from which both clients will update.
import socket
import pickle
import sys
import threading
import queue
from threading import Thread
class Server(threading.Thread):
def __init__(self, ip):
self.gameboards = [[[0 for i in range(10)] for j in range(10)] for k in range (4)]
self.HOST = ip
self.PORT = 58008
self.status = 1
self.turn = 1
self.client1_submit = False
self.client2_submit = False
self.preamble = (self.status, self.turn)
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ('Created Socket')
try:
self.s.bind((self.HOST, self.PORT))
except Exception as ex:
print ('Failed to bind to port. Selfdestructing.')
sys.exit(1)
print ('Socket bound')
# timeout after 60 seconds
self.s.settimeout(60)
def listen(self):
debug = False
q = queue.Queue()
x = True
while x:
self.preamble = (self.status, self.turn)
self.s.listen(2)
if debug: print('Listening for connection...')
#wait to accept a connection - blocking call
self.conn, addr = self.s.accept()
if debug: print('Connected by', addr)
t = Thread(target=clientthread, args=(self.conn,self.preamble,self.gameboards, q))
t.start()
sent_move = q.get()
if debug: print ("queue", q.qsize())
while q.qsize() > 1:
if sent_move: break
sent_move = q.get()
if sent_move:
if not self.client1_submit:
self.gameboards = sent_move
self.client1_submit = True
self.turn = 2
elif not self.client2_submit:
self.gameboards[2] = sent_move[0]
self.client2_submit = True
self.turn = 1
self.status = 2
else:
if self.turn == 1:
self.gameboards[1] = sent_move[1]
self.gameboards[3] = sent_move[2]
self.turn = 2
else:
self.gameboards[3] = sent_move[1]
self.gameboards[1] = sent_move[2]
self.turn = 1
self.stop()
def stop(self):
self.s.close()
def clientthread(conn, preamble, gameboards,q):
debug = False
status, turn = preamble
ePreamble = "{0}.{1}".format(status, turn).encode()
if debug:
print("Sending preamble...")
conn.send(ePreamble)
if debug:
print ("Recieving preamble.")
ePreambleRecv = conn.recv(1024)
if (ePreamble == ePreambleRecv):
if debug:
print ("Preamble OK")
if debug:
print("Sending data...")
for board in gameboards:
pData = pickle.dumps(board)
conn.send(pData)
pDataRecv = conn.recv(1024)
if (pDataRecv == pDataRecv):
if debug:
print ("Board OK")
# if still in initial setup
try:
submitted = []
for x in range(0,4):
if debug:
print ('Getting board...')
pData = conn.recv(1024)
data = pickle.loads(pData)
conn.send(pData)
if debug:
print ('Recieved!')
submitted.append(data)
except:
if (submitted == []):
# No move to submit, just close connection and return
if debug:
print ("Client quit without submitting a move.")
else:
print("Invalid submit?")
conn.close()
q.put(submitted)
if __name__ == "__main__":
serv = Server('192.168.1.107')
servthread = Thread(target=serv.listen, args=())
servthread.start()