我正在编写一个网络数字猜谜游戏,我可以用它做一点帮助。除了处理多个客户端之外,我的服务器还需要接受来自Admin客户端的连接。 Admin客户端显示连接到服务器的播放器客户端的IP地址和端口号列表。我知道我需要实现线程才能实现这一点。
到目前为止,这是我的代码。我不确定需要多少线程以及如何将连接的播放器客户端的信息传递给线程。
{{1}}
答案 0 :(得分:1)
所以这是一个解决方案。它应该有效,但有些事情需要注意:
我没有尝试改进您的代码只是为了添加您要求的内容,因此它可能不是最佳解决方案,至少它还没有完成。
这是它的工作原理:你创建2个TCPServer实例,一个用于处理管理连接,另一个用于客户端。每个实例都有一个BaseRequestHandler 基本上,服务器侦听连接并自动启动一个新线程,为每个线程调用请求处理程序。
现在要共享数据,您可以使用任何变量,这里是字典,并在线程之间共享。 通过将字典设置为服务器成员,您可以从请求处理程序访问字典。 为了保护共享字典上的访问,有一个锁(I.E.一个互斥锁),它就像字典一样被共享。
您可以使用:
评论如果需要我会更新。
import threading
import socketserver
import ssl
import random
class ThreadedTCPAdminRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
ts = self.request # replaced the ssl connection for simpler code
msg = ts.recv(80).decode()
# Here should be some kind of loop to be able to handle multiple request of the same admin client
# like 'Hello' followed by 'Who'
if msg == 'Hello':
ts.send('Admin-Greetings\r\n'.encode())
elif msg == 'Who':
with self.server.addressesLock:
# get a local copy of the dict and quickly release the lock
socket_addresses = self.server.addresses.copy()
client_string=''
# print the list of threads with their address:port
for threadName, socket_addresse in socket_addresses.items():
client_string += threadName + ' ' + socket_addresse + '\r\n'
# the admin handler doesn't anything if the following line is commented
# ts.send(client_string.encode())
# for simpler test, that way you can see the connexion listing is working
# even if there are conection problems
print(client_string)
ts.send('plop'.encode())
class ThreadedTCPClientRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
cur_thread = threading.current_thread().name
with self.server.addressesLock: # use a lock to protect the access to the shared dict
# add name of the thread ad key and the address:port as value in the global dict
self.server.addresses[cur_thread] = self.client_address[0] + ':' + str(self.client_address[1])
score_count = 0
guess = 0
if (self.request.recv(80).decode()) == 'Hello':
self.request.send('Greetings\r\n'.encode())
goal = random.randrange(1, 21)
while guess != goal:
guess = self.request.recv(80).decode()
guess = int(guess[7:len(guess) - 2])
if guess == goal:
self.request.send('Correct\r\n'.encode())
elif guess in range(goal-2,goal +2):
self.request.send('Close\r\n'.encode())
else:
self.request.send('Far\r\n'.encode())
with self.server.addressesLock: # use a lock to protect the access to the shared dict
del self.server.addresses[cur_thread] # delete the thread entry in the dict
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
if __name__ == "__main__":
C_HOST, C_PORT = 'localhost', 4000
A_HOST, A_PORT = 'localhost', 4001
clientServer = ThreadedTCPServer((C_HOST, C_PORT), ThreadedTCPClientRequestHandler)
adminServer = ThreadedTCPServer((C_HOST, A_PORT), ThreadedTCPAdminRequestHandler)
# Start a thread for each the server (client and admin) -- those threads will then start one
# more thread for each request
clientServer_thread = threading.Thread(target=clientServer.serve_forever)
adminServer_thread = threading.Thread(target=adminServer.serve_forever)
addresses = {} # create a dict to store the addresses of connected clients
addressesLock0 = threading.Lock() # create a lock to protect access to the dict
clientServer_thread.daemon = True # client will terminate when main terminate
clientServer.addresses = addresses # share the addreses dict
clientServer.addressesLock = addressesLock0 # share the lock
adminServer_thread.daemon = True
adminServer.addresses = addresses
adminServer.addressesLock = addressesLock0
try:
# strart servers
clientServer_thread.start()
print("clientServer loop running in thread:", clientServer_thread.name)
adminServer_thread.start()
print("adminServer loop running in thread:", adminServer_thread.name)
input('Press Enter to exit...\r\n') # wait input to end the program
finally:
# stop servers
clientServer.shutdown()
clientServer.server_close()
adminServer.shutdown()
adminServer.server_close()
exit(0)