【Python】使用socket库实现server-client通讯的联机对战游戏(一)


socket单对单通讯

socket是Python内建库之一,用途就是网络通讯。作为实验,我们考虑两个Python程序之间的通讯,一个作为服务器,一个作为客户端,客户端向服务器发送一串字符,服务器收到后将原字符串大写后传回,直到客户端发送空信息,服务器退出。

服务器端代码:

import socket

ip_port = ('', 8888) # 这个tuple的第一项是ip地址,第二项是端口
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 定义socket类型,网络通信,TCP
s.bind(ip_port) # 套接字绑定ip和端口
s.listen(1) # 开始监听连接请求
conn, addr = s.accept() # 接受连接请求,conn是一个新的套接字,addr是客户端地址
conn.sendall('Hello from the server!'.encode('utf-8')) # 发送打招呼信息,并且用utf-8编码
while True:
    try:
        data = conn.recv(1024).decode('utf-8') # 接受数据并使用utf-8解码
        if not data:
            break # 如果数据为空就退出
        conn.sendall(data.upper().encode('utf-8')) # 把数据大写后返回
    except Exception as e: # 如果数据传输出错
        print(e)
        exit(1)
conn.close() # 关闭套接字

客户端代码:

import socket

ip_port = ('localhost', 8888) # 服务器ip和端口
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) # 定义socket类型,网络通信,TCP
try:
    s.connect(ip_port) # 尝试连接服务器
except Exception as e: # 如果连接失败socket.socket.connect会抛出错误
    print(e)
    exit(1)
data = s.recv(1024).decode('utf-8') # 接受服务器的问候
print(data)
while True:
    try:
        msg = input('>>> ') # 此时用户可以在运行客户端的控制台中输入内容
        s.sendall(msg.encode('utf-8')) # 将消息发送
        if not msg:
            break # 如果数据为空就退出
        data = s.recv(1024).decode('utf-8') # 接受服务器的结果
        print(data)
    except Exception as e: # 如果数据传输出错
        print(e)
        exit(1)
s.close() # 关闭套接字

运行结果:

运行结果

socketserver多对一通讯

由于我的目的是打算写一个联机对战游戏,那么一个服务器需要同时和多个(至少是两个)客户端建立连接。一个很容易想到的做法就是服务器多线程。好在Python已经帮我们封装好了多线程和socket库——socketserver库。

socketserver库的用法和socket几乎一模一样,而且由于只有服务器端需要多线程,所以只需要更改server.py即可。

下面是server.py的代码:

import socketserver

ip_port = ('', 10888)

class MyServer(socketserver.BaseRequestHandler):
    def handle(self): # 重写RequestHandler中的handle方法用来处理请求
        print("conn is :", self.request)  # conn
        print("addr is :", self.client_address)  # addr

        self.request.sendall('Hello from the server!'.encode('utf-8'))
        while True: # 处理方面的逻辑都是一样的
            try:
                data = self.request.recv(1024).decode('utf-8')
                if not data:
                    break
                self.request.sendall(data.upper().encode('utf-8'))
            except Exception as e:
                print(e)
                break
        
        print("disconnected with", self.client_address)
        
if __name__ == '__main__':
    s = socketserver.ThreadingTCPServer(ip_port, MyServer) # 建立TCP协议套接字
    
    # 使用s.serve_forever()接受无穷次连接(需要按下Ctrl+C中断)
    # 也可以使用一次s.handle_request()接受一次连接
    s.serve_forever() 

运行结果:

Server服务器结果

Client客户端结果

服务器内部数据传输

现在我们已经解决了服务器和客户端之间的数据传输问题了,但是这又引入了新的问题:服务器用多线程和客户端交流,但是socketserver封装的太好了,想要直接从外部操作各个线程显然不显示,那么如何进行服务器各个线程之间的交流呢?

请听下回分解……

😀
–601b31d481ac0ffb36c20bb7a4ceb023–


评论
  目录