Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import socket
- import sys
- from threading import Thread
- SERVER_CONFIRMATION = ''
- SERVER_MOVE = '102 MOVE\a\b'.encode('utf-8')
- SERVER_TURN_LEFT = '103 TURN LEFT\a\b'.encode('utf-8')
- SERVER_TURN_RIGHT = '104 TURN RIGHT\a\b'.encode('utf-8')
- SERVER_PICK_UP= '105 GET MESSAGE\a\b'.encode('utf-8')
- SERVER_LOGOUT= '106 LOGOUT\a\b'.encode('utf-8')
- SERVER_OK= '200 OK\a\b'.encode('utf-8')
- SERVER_LOGIN_FAILED= '300 LOGIN FAILED\a\b'.encode('utf-8')
- SERVER_SYNTAX_ERROR= '301 SYNTAX ERROR\a\b'.encode('utf-8')
- SERVER_LOGIC_ERROR= '302 LOGIC ERROR\a\b'.encode('utf-8')
- CLIENT_RECHARGING = 'RECHARGING\a\b'
- CLIENT_FULL_POWER = 'FULL POWER\a\b'
- CLIENT_USERNAME_LEN = 10
- CLIENT_CONFIRMATION_LEN = 5
- CLIENT_OK_LEN = 10
- CLIENT_RECHARGING_LEN = 10
- CLIENT_FULL_POWER_LEN = 10
- CLIENT_MESSAGE_LEN = 98
- KLIENT_KEY = 45328
- SERVER_KEY = 54621
- UNINICIALIZED = -1
- UP = 0
- RIGHT = 1
- DOWN = 2
- LEFT = 3
- #Robot a definovani vsech jeho moznych pohybu
- class Robot:
- def __init__(self):
- self.visitedBoxCorner = False
- self.direction = UNINICIALIZED
- self.previousCoordinates = None
- self.previouslyPickedUpTreasure = False
- self.goUp = True
- self.moveRight = True
- self.moveRightX = -2
- def RightDirection(self,x,y,goalX,goalY):
- if goalY > y:
- return UP
- if goalY < y:
- return DOWN
- if goalX > x:
- return RIGHT
- if goalX < x:
- return LEFT
- def TurnLeftOrRight(self,goalDirection):#
- if self.direction == goalDirection:
- return SERVER_TURN_RIGHT
- if self.direction - goalDirection == 1 or self.direction == UP and goalDirection == LEFT:
- self.direction = (self.direction - 1) % 4
- return SERVER_TURN_LEFT
- else:
- self.direction = (self.direction + 1) % 4
- return SERVER_TURN_RIGHT
- def VisitCorner(self,x,y):
- correctDirection = self.RightDirection(x,y,-2,-2)
- self.previousCoordinates = (x, y)
- if correctDirection == self.direction:
- return SERVER_MOVE
- else:
- return self.TurnLeftOrRight(correctDirection)
- def SetAnotherGoalCoordinatesInBox(self,x,y):
- if y != 2 and self.goUp:
- return x,2
- if y == 2 and self.goUp and x == self.moveRightX:
- return x+1,y
- if y == 2 and self.goUp and x > self.moveRightX:
- self.moveRightX = x
- self.goUp = False
- return x, -2
- if y != -2 and not self.goUp:
- return x, -2
- if y == -2 and not self.goUp and x == self.moveRightX:
- return x+1,y
- if y == -2 and not self.goUp and x > self.moveRightX:
- self.moveRightX = x
- self.goUp = True
- return x, 2
- def LookForTreasure(self,x,y):
- if not self.previouslyPickedUpTreasure:
- self.previouslyPickedUpTreasure = True
- self.previousCoordinates = (x, y)
- return SERVER_PICK_UP
- else:
- goalX,goalY = self.SetAnotherGoalCoordinatesInBox(x,y)
- correctDirection = self.RightDirection(x, y, goalX, goalY)
- if correctDirection == self.direction:
- self.previouslyPickedUpTreasure = False
- self.previousCoordinates = (x, y)
- return SERVER_MOVE
- else:
- self.previousCoordinates = (x, y)
- return self.TurnLeftOrRight(correctDirection)
- def Move(self,x,y):
- if x == 999999 and y == 999999:
- return SERVER_MOVE
- if self.previousCoordinates == None:
- self.previousCoordinates = (x,y)
- return SERVER_MOVE
- if self.direction == UNINICIALIZED and self.previousCoordinates == (x,y):
- self.previousCoordinates = (x,y)
- return SERVER_MOVE
- if self.direction == UNINICIALIZED:
- if x > self.previousCoordinates[0]:
- self.direction = RIGHT
- elif x < self.previousCoordinates[0]:
- self.direction = LEFT
- elif y < self.previousCoordinates[1]:
- self.direction = DOWN
- elif y > self.previousCoordinates[1]:
- self.direction = UP
- if not self.visitedBoxCorner and (x,y) == (-2,-2):
- self.visitedBoxCorner = True
- if self.visitedBoxCorner:
- return self.LookForTreasure(x,y)
- return self.VisitCorner(x,y)
- def ExtractData(DataWithAdditionalStuff,connection,stage,treasureMessage):
- DataWithAdditionalStuff = DataWithAdditionalStuff.decode('utf-8')
- data = ''
- if DataWithAdditionalStuff == '':
- return data,0
- counter = 0
- while DataWithAdditionalStuff[len(DataWithAdditionalStuff) - 2] != '\a' or DataWithAdditionalStuff[len(DataWithAdditionalStuff) - 1] != '\b':
- if '\a\b' not in DataWithAdditionalStuff and not CheckOnlyLength(DataWithAdditionalStuff,stage,treasureMessage):
- return DataWithAdditionalStuff, 0
- if '\0' in DataWithAdditionalStuff:
- break
- connection.settimeout(1)
- tmp = connection.recv(1000)
- tmp = tmp.decode('utf-8')
- DataWithAdditionalStuff += tmp
- if DataWithAdditionalStuff[len(DataWithAdditionalStuff) - 2] != '\a' or DataWithAdditionalStuff[len(DataWithAdditionalStuff) - 1] != '\b':
- return ['2','ERROR'], 2
- while True:
- if DataWithAdditionalStuff[counter] == '\a' and DataWithAdditionalStuff[counter+1] == '\b':
- if counter == len(DataWithAdditionalStuff) - 2:
- return data,0
- else:#multiple messages
- data = [data]
- anotherData = ''
- counter += 2
- while True:
- if DataWithAdditionalStuff[counter] == '\a' and DataWithAdditionalStuff[counter + 1] == '\b':
- if counter == len(DataWithAdditionalStuff) - 2:
- data.append(anotherData)
- return data,len(data)
- else:
- data.append(anotherData)
- counter += 2
- anotherData = ''
- else:
- anotherData += DataWithAdditionalStuff[counter]
- counter += 1
- else:
- data += DataWithAdditionalStuff[counter]
- counter += 1
- def EncapsulateMessage(data):
- data = str(data)
- data += '\a\b'
- data = data.encode('utf-8')
- return data
- def ConfirmationFromServer(name):
- mySum = 0
- for myChar in name:
- mySum+=ord(myChar)
- mySum *= 1000
- myHash = mySum%65536
- mySum += SERVER_KEY
- mySum %= 65536
- mySum = EncapsulateMessage(mySum)
- return mySum, myHash
- def CompareHashes(number,hash):
- number += 65536 - KLIENT_KEY
- number %= 65536
- if number == hash:
- return True
- return False
- def ExtractCoordinates(data):
- x = 0
- y = 0
- tmp = data.split(' ')
- x = int(tmp[1])
- y = int(tmp[2])
- return x,y
- def CheckOnlyLength(data,stage,treasureMessage):
- myLen = len(data)
- if myLen and data[myLen-1] == '\a':
- myLen -= 1
- if 'RECHARGING' in data or 'FULL POWER' in data:
- return myLen <= CLIENT_RECHARGING_LEN
- if stage == 1:
- return myLen <= CLIENT_CONFIRMATION_LEN
- else:
- if data == '':
- return True
- if stage == 0:
- return myLen <= CLIENT_USERNAME_LEN
- if stage == 2 and not treasureMessage:
- return myLen <= CLIENT_OK_LEN
- return myLen <= CLIENT_MESSAGE_LEN
- def CheckLengthAndSyntax(data,stage,treasureMessage):
- if 'RECHARGING' in data or 'FULL POWER' in data:
- return len(data) <= CLIENT_RECHARGING_LEN
- if stage == 1:
- if len(data) <= CLIENT_CONFIRMATION_LEN:
- return not (' ' in data)
- return len(data) <= CLIENT_CONFIRMATION_LEN
- else:
- if data == '':
- return True
- if stage == 0:
- return len(data) <= CLIENT_USERNAME_LEN
- if stage == 2 and not treasureMessage:
- if len(data) <= CLIENT_OK_LEN:
- try:
- if not (data[0] == 'O' and data[1] == 'K' and data[2] == ' '):
- return False
- tmp = data.split(' ')
- tmp[1] = int(tmp[1])
- tmp[2] = int(tmp[2])
- a = tmp[0] + ' ' + str(tmp[1]) + ' ' + str(tmp[2])
- if a != data:
- return False
- except Exception as ex:
- return False
- return len(data) <= CLIENT_OK_LEN
- return len(data) <= CLIENT_MESSAGE_LEN
- class TCP_Server:
- def __init__(self):
- self.listOfThreads = []
- def Communicate(self,mySocket):
- while True:
- # Wait for a connection
- print('waiting for a connection')
- connection, client_address = mySocket.accept()
- connection.settimeout(1)
- t1 = Thread(target = self.CommunicateSingleThread, args = (mySocket,connection,client_address))
- t1.start()
- self.listOfThreads.append(t1)
- def CommunicateSingleThread(self,mySocket,connection,client_address):
- myHash = 0
- stage = 0
- recharge = False
- multipleMessages = False
- robot = Robot()
- data = ''
- counter = 0
- cnt = 0
- try:
- print('connection from', client_address)
- # Receive the data
- while True:
- if not multipleMessages:
- data = connection.recv(1000)
- print('Received {!r}'.format(data))
- temporaryData, cnt = ExtractData(data, connection, stage,
- robot.previouslyPickedUpTreasure)
- if cnt:
- multipleMessages = True
- data = temporaryData[counter]
- counter += 1
- cnt -= 1
- if not cnt:
- counter = 0
- multipleMessages = False
- else:
- data = temporaryData
- if data == SERVER_SYNTAX_ERROR or not CheckLengthAndSyntax(data, stage,
- robot.previouslyPickedUpTreasure):
- connection.sendall(SERVER_SYNTAX_ERROR)
- break
- if data == 'RECHARGING':
- connection.settimeout(5)
- recharge = True
- continue
- if data == 'FULL POWER':
- recharge = False
- connection.settimeout(1)
- continue
- if recharge:
- connection.sendall(SERVER_LOGIC_ERROR)
- break
- if stage == 0:
- SERVER_CONFIRMATION, myHash = ConfirmationFromServer(data)
- connection.sendall(SERVER_CONFIRMATION)
- stage += 1
- elif stage == 1:
- if CompareHashes(int(data), myHash):
- connection.sendall(SERVER_OK)
- connection.sendall(robot.Move(999999, 999999))
- stage += 1
- else:
- connection.sendall(SERVER_LOGIN_FAILED)
- break
- elif stage == 2:
- if data != '' and data[0] == 'O' and data[1] == 'K' and data[2] == ' ':
- x, y = ExtractCoordinates(data)
- connection.sendall(robot.Move(x, y))
- else:
- if data == '':
- connection.sendall(
- robot.Move(robot.previousCoordinates[0], robot.previousCoordinates[1]))
- else:
- connection.sendall(SERVER_LOGOUT)
- break
- except socket.timeout:
- print('Caught timeout')
- finally:
- # Clean up the connection
- connection.close()
- server = TCP_Server()
- #create socket
- socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
- server_address = ('local_host', 10000)
- socket.bind(server_address)
- socket.listen(1)
- server.Communicate(socket)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement