【Python五子棋】基于Socket的多人五子棋-通信部分
这篇博客中介绍了基于Python语言编写的多人五子棋(两人或三人)游戏主体框架中的多人联机通信部分,考虑到多人五子棋通常情况下是在本地网络下进行,因此我选择了使用连接更加稳定的TCP/IP协议的socket作为五子棋对局过程中多机通讯的主要手段。
由于我们小组项目中选择的五子棋对局结构是CS结构,下面的博客主要介绍了Server端从开始到建立连接并开始游戏再到最终的判断胜负并返回过程中的代码逻辑,此处展示的代码只是一个包含有基本逻辑的中间工程代码,并非最终完成的代码部分,如果想要完整的多人联机五子棋和AI算法代码的话可以去我的CSDN共享资源中寻找完整的压缩包。
话不多说,下面直接提供通信部分框架的主要代码逻辑,采用Socket依次轮询并发送指定信息实现棋子位置的选择。
可以提供的代码改进部分提示:
①为了防止Server和Client之间Socket传递信息出现粘连,可以使用time.sleep()函数设置一个1秒以内的短延时;
②为了保证不在当前回合的client能接收到当前回合的client下子的位置信息,可以加上附加的判断部分实现这一功能(这里提供的中间代码没有包含这个功能)
③需要注意加上棋局是否完结的判断函数,这里的中间代码预留了这个借口但并没有详细定义这个函数
下面提供的是Server端示范逻辑的中间代码:
import socket
#判断输赢函数,此处未给出详细定义
def judgeResult(i, j, value):
pass
def whowins( x, y, i, win, winclient): #函数的形参为s1,s2,s3为对三个client端的socket连接,win为胜利指示变量,i为胜利者的client编号
mark = judgeResult(x, y, i)
if(mark==1):
print("当前棋局已经分出胜负,获胜者是{}!".format(i))
win=1
winclient=i
elif(mark==0):
win=0
print("游戏继续!")
#初始化并创建监听socket部分
ip1=input("请输入主机ip地址")
ip_port = (ip1,1234) #设置主机IP地址和端口
back_log = 5 #设置客户端最大监听数量
buf_size = 1024 #设置默认buf文本区大小
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 初始化TCP连接的socket
s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) # 对socket的配置重用ip和端口号
s.bind(ip_port) #绑定端口号和socket
s.listen(back_log) #设置socket端监听对象链接
print("成功创建socket,等待client端链接中...")
#设置client连接顺序部分
i=0 #设置i为表示client连接顺序的标记变量
j=0 #设置j为标志断开连接的指示变量
while True:
c,address = s.accept() #阻塞式等待client端的链接
if(i==0):
i=1
msg0=("{}".format(i))
c.send(msg0.encode('utf-8')) #向client端传递客户机编号
addr1=address
c1=c #第一次监听到连接时,设置连接为client1
print("接收到来自{}地址的client端连接,连接编号为{}".format(address,i))
elif(i>0):
if((address!=addr1) & (i==1)):
i=2
msg0=("{}".format(i))
c.send(msg0.encode('utf-8')) #向client端传递客户机编号
addr2=address
c2=c #监听到不同的的连接时,设置连接为client2
print("接收到来自{}地址的client端连接,连接编号为{}".format(address,i))
elif((address!=addr1) & (address!=addr2) & (i==2)):
i=3
msg0=("{}".format(i))
c.send(msg0.encode('utf-8')) #向client端传递客户机编号
addr3=address
c3=c #监听到第三个不同ip地址的连接时,设置连接为client3
print("接收到来自{}地址的client端连接,连接编号为{}".format(address,i))
elif(i==3):
print("已达到最大连接client数量,额外连接被挂起!")
msg0=("end")
c.send(msg0.encode('utf-8')) #向client端传递终止连接命令
#连接的玩家数不为最大值时,确定加入的电脑数量
if(i!=3):
start=input("当前连接的玩家数为{}人,是否添加电脑?Y/N".format(i))
if(start=='Y'):
numc=int (input("可添加的电脑玩家数量上限为{}".format(3-i)))
if(i+numc<=3):
i=i+numc
gamestart=1
else:
print("您输入的电脑数量有误!")
elif(i==2):
start2=input("当前连接数为2,确认开始2人的PVP游戏吗?-Y/N")
if(start2=='Y'):
gamestart=1
elif(i==3):
print("当前连接的玩家数量已满3人,游戏开始!")
gamestart=1
#判断当client数量已经满足要求时,开始轮询过程
if(i==2 & gamestart == 1):
print("2人游戏开始!")
win=0
winclient=0 #初始化棋盘胜负状态变量win和winclient
while 1:
i=1
msg='1'
c1.send(msg.encode('utf-8'))
msgw=("{}".format(win))
c1.send(msgw.encode('utf-8'))
msgw=("{}".format(winclient))
c1.send(msgw.encode('utf-8'))
msgx1 = c1.recv(buf_size)
if(msgx1=='end'):
print("Client1已关闭")
else:
print('服务器接受到来自client1端行坐标为{}'.format(msgx1.decode('utf-8')))
msgy1 = c1.recv(buf_size)
print('服务器接受到来自client1端列坐标为{}'.format(msgy1.decode('utf-8')))
x1=msgx1
y1=msgy1
whowins( x1, y1, i, win, winclient)
i=2
msg='2'
c2.send(msg.encode('utf-8'))
msgw=("{}".format(win))
c2.send(msgw.encode('utf-8'))
msgw=("{}".format(winclient))
c2.send(msgw.encode('utf-8'))
msgx2 = c2.recv(buf_size)
if(msgx2=='end'):
print("Client2已关闭")
else:
print('服务器接受到来自client2端行坐标为{}'.format(msgx2.decode('utf-8')))
msgy2 = c2.recv(buf_size)
print('服务器接受到来自client2端列坐标为{}'.format(msgy2.decode('utf-8')))
x2=msgx2
y2=msgy2
whowins( x2, y2, i, win, winclient)
#循环轮次判定结束
if (win == 0):
continue
else:
print('通信已经结束,连接断开')
j=1
break
elif(i==3 & gamestart == 1):
print("3人游戏开始!")
win=0
winclient=0 #初始化棋盘胜负状态变量win和winclient
while 1:
i=1
msg='1'
c1.send(msg.encode('utf-8'))
msgw=("{}".format(win))
c1.send(msgw.encode('utf-8'))
msgw=("{}".format(winclient))
c1.send(msgw.encode('utf-8'))
msgx1 = c1.recv(buf_size)
if(msgx1=='end'):
print("Client1已关闭")
else:
print('服务器接受到来自client1端行坐标为{}'.format(msgx1.decode('utf-8')))
msgy1 = c1.recv(buf_size)
print('服务器接受到来自client1端列坐标为{}'.format(msgy1.decode('utf-8')))
x1=msgx1
y1=msgy1
whowins( x1, y1, i, win, winclient)
i=2
msg='2'
c2.send(msg.encode('utf-8'))
msgw=("{}".format(win))
c2.send(msgw.encode('utf-8'))
msgw=("{}".format(winclient))
c2.send(msgw.encode('utf-8'))
msgx2 = c2.recv(buf_size)
if(msgx2=='end'):
print("Client2已关闭")
else:
print('服务器接受到来自client2端行坐标为{}'.format(msgx2.decode('utf-8')))
msgy2 = c2.recv(buf_size)
print('服务器接受到来自client2端列坐标为{}'.format(msgy2.decode('utf-8')))
x2=msgx2
y2=msgy2
whowins( x2, y2, i, win, winclient)
msg='3'
c3.send(msg.encode('utf-8'))
msgw=("{}".format(win))
c3.send(msgw.encode('utf-8'))
msgw=("{}".format(winclient))
c3.send(msgw.encode('utf-8'))
msgx3 = c3.recv(buf_size)
if(msgx3=='end'):
print("Client3已关闭")
else:
print('服务器接受到来自client3端行坐标为{}'.format(msgx3.decode('utf-8')))
msgy3 = c1.recv(buf_size)
print('服务器接受到来自client3端列坐标为{}'.format(msgy3.decode('utf-8')))
x3=msgx3
y3=msgy3
whowins( x3, y3, i, win, winclient)
#循环轮次判定结束
if (win == 0):
continue
else:
print('通信已经结束,连接断开')
j=1
break
if(j==1):
break
s.close() #关闭监听主socket,服务端程序结束
print("连接已断开!")
这里是Client端的逻辑示范中间代码:
import socket
buf_size=1024
p = socket.socket(socket.AF_INET,socket.SOCK_STREAM)#创建socket并设置server端连接的IP地址和端口
ip1=(input("请输入server端的IP地址"))
p.connect((ip1,1234))
msg = p.recv(buf_size) #接收server端反馈的信息编号
if(msg!='end'):
print("已连接到ip为{}的server端,本机编号为{}".format(ip1,msg.decode('utf-8'))) # 连接成功时将server端ip地址反馈到client端
num=msg #定义client端编号为num
elif(msg=='end'):
print("server端连接数量已达上限!当前连接断开!")
#成功连接时开启主循环
if(msg!='end'):
while 1:
msg = p.recv(buf_size) # 接收server端发送的当前client编号
if(num!=msg):
continue
msg0 = p.recv(buf_size) #接受广播信息-获胜情况和游戏进行状态
msg1 = p.recv(buf_size)
if msg0 =='1':
print("Player{} wins!".format(msg1))
msg=('end')
p.send(msg.encode('utf-8')) #向server传递关机信息
break
elif msg == '0':
msgx=input("请输入传递给server端的落子坐标行信息")
p.send(msgx.encode('utf-8'))
msgy=input("请输入传递给server端的落子坐标列信息")
p.send(msgy.encode('utf-8'))
print("信息已经发送至server端!")
p.close()
print("连接已断开!")
完整的代码可以在我共享的资源文件中找到。