# coding:utf-8 import socket import sys import json import uuid import time from threading import Thread, Lock if(sys.version[:1] == "3"): import queue as Queue from _thread import * else: import Queue from thread import * class Config: SOCKET_HOST = '127.0.0.1' # Symbolic name meaning all available interfaces SOCKET_PORT = 50005 # Arbitrary non-privileged port MAX_WAITING_TIME = 180 MAX_THNIKING_TIME = 60 MAX_TOTAL_TIME = 600 class Client: def __init__(self, conn, addr, name, side, time, total): self.conn = conn self.addr = addr self.name = name self.side = side self.time = time self.total = total mutex = Lock() mutex_playing = Lock() playing_ones = {} waiting_players = Queue.Queue() #init queues #for games in range(1, 10): # waiting_players[games] = Queue.Queue() def load_config(): with open('config.txt', 'r') as f: for line in f.readlines(): line = line.strip() if line.find('SOCKET_HOST=') >= 0: Config.SOCKET_HOST = line[line.index('=') + 1 : ] elif line.find('SOCKET_PORT=') >= 0: Config.SOCKET_PORT = int(line[line.index('=') + 1 : ]) elif line.find('MAX_WAITING_TIME=') >= 0: Config.MAX_WAITING_TIME = int(line[line.index('=') + 1 : ]) elif line.find('MAX_THNIKING_TIME=') >= 0: Config.MAX_THNIKING_TIME = int(line[line.index('=') + 1 : ]) elif line.find('MAX_TOTAL_TIME=') >= 0: Config.MAX_TOTAL_TIME = int(line[line.index('=') + 1 : ]) else: pass def get_counterpart_from(waiting_ones): counterpart = None mutex.acquire() if not waiting_ones.empty(): counterpart = waiting_ones.get() mutex.release() return counterpart def to_wait_in_queue(client, the_queue): mutex.acquire() the_queue.put(client) mutex.release() def remove_one_from_queue(the_queue): mutex.acquire() if (the_queue.qsize() == 1): the_queue.get() mutex.release() def send_msg_to(client, msg): packet = json.dumps(msg) if (sys.version[:1] == "3"): packet = packet.encode('utf-8') #print(client.addr[0] + ":" + str(client.addr[1]) + "\t" + str(msg)) client.conn.send(packet) def __start_match_between(client0, client1): match_uuid = str(uuid.uuid4()) mutex_playing.acquire() playing_ones[match_uuid] = (client0, client1) mutex_playing.release() client0.side = 0 client0.time = Config.MAX_THNIKING_TIME client0.total = Config.MAX_TOTAL_TIME client1.side = 1 client1.time = -1 client1.total = Config.MAX_TOTAL_TIME msg0 = { "status": 1, "counterpart_name": client1.name, "game_id": match_uuid, "side": client0.side, "think_time": Config.MAX_THNIKING_TIME, "total_time": Config.MAX_TOTAL_TIME, } send_msg_to(client0, msg0) msg1 = { "status": 1, "counterpart_name": client0.name, "game_id": match_uuid, "side": client1.side, "think_time": Config.MAX_THNIKING_TIME, "total_time": Config.MAX_TOTAL_TIME, } send_msg_to(client1, msg1) def join_game_handler(msg, addr, conn): new_client = Client(conn, addr, msg['name'], -1, -1, -1) #game_type = msg["id"] #the_queue = waiting_players[game_type] counterpart = get_counterpart_from(waiting_players) if not counterpart: #wait to_wait_in_queue(new_client, waiting_players) return else: #counterpart=get_counterpart_from(waiting_players[game_type]) __start_match_between(new_client, counterpart) def quit_game_handler(msg): match_uuid = msg['game_id'] if match_uuid is None: remove_one_from_queue(waiting_players) return pairs = None mutex_playing.acquire() if (match_uuid in playing_ones): pairs = playing_ones[match_uuid] del playing_ones[match_uuid] mutex_playing.release() if pairs is not None: if(pairs[0].side == msg['side']): to_notify = pairs[1] else: to_notify = pairs[0] msg = { "status": 2, #exit "game_id": match_uuid, "side": msg['side'], "request": msg['request'], } send_msg_to(to_notify, msg) def timer_thread(): while True: time.sleep(1) mutex_playing.acquire() for game_id in list(playing_ones.keys()): (client0, client1) = playing_ones[game_id] #print("%d - %d" % (client0.time, client1.time)) if (client0.time < 0): client = client1 else: client = client0 if (client.time == 0 or client.total == 0): msg = { "status": 3, #timeout exit "game_id": game_id, "side": client.side, } send_msg_to(client0, msg) send_msg_to(client1, msg) del playing_ones[game_id] else: client.time -= 1 client.total -= 1 mutex_playing.release() def transfer_message(msg): match_uuid = msg['game_id'] pairs = playing_ones[match_uuid] if(pairs[0].side == msg['side']): to_notify = pairs[1] pairs[0].time = -1 else: to_notify = pairs[0] pairs[1].time = -1 to_notify.time = Config.MAX_THNIKING_TIME send_msg_to(to_notify, msg) def client_thread(conn, addr): while True: data = conn.recv(1024) if not data: break print(data) data = json.loads(data) if not 'type' in data: transfer_message(data['msg']) continue if data['type'] == 0: join_game_handler(data['msg'], addr, conn) continue elif data['type'] == 1: transfer_message(data['msg']) continue elif data['type'] == 2: quit_game_handler(data['msg']) break elif data['type'] == 3: break else: #delivering message between the two clients transfer_message(data['msg']) continue #came out of loop conn.close() def main(): load_config() server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print('Socket server created') #try: server.bind((Config.SOCKET_HOST, Config.SOCKET_PORT)) #except (socket.error, msg): # print ('Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]) # sys.exit() print('Socket bind complete') server.listen(10) print('Socket now listening') #now keep talking with the client start_new_thread(timer_thread, ()) while True: #! 监听本体 #wait to accept a connection - blocking call conn, addr = server.accept() print ('Connected with ' + addr[0] + ':' + str(addr[1])) #start new thread takes 1st argument as a function name to be run, second is the tuple of arguments to the function. start_new_thread(client_thread, (conn, addr)) server.close() if __name__ == '__main__': main()