(关注“测试开发自动化” 弓中皓,获取更多学习内容)
SOCKET它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。
我们就用上面的模式,来开发一个聊天室工具,主要的开发模块包括两部分:
可以部署在同一电脑上,由于我只有一台电脑,所以我将服务端和客户端都部署在了我自己的电脑上。你也可以部署在同一局域网的不同电脑上,或使用其他的不同服务器进行部署,效果展示:
如果你们公司的网络是不允许接入互联网的,那么你可以偷偷做一个局域网内的聊天小软件,用于你跟心爱的女孩子之间聊天。哈哈哈哈。。
创建服务端的流程大致可以分为以下几个步骤:
1)创建客户端套接字(socket)对象
2)绑定IP地址和端口号
3)设置监听
4)等待接受客户端的连接请求
5)接受数据
6)发送数据
7)关闭客户端套接字(socket)
该部分主要用于初始化服务端,创建一个Severt类,它不断监听客户端的发送的请求。
class Server:
def __init__(self):
self.server = socket.socket() # 创建客户端套接字(socket)对象
self.server.bind(("192.168.20.164", 8989)) # 绑定IP地址和端口号
self.server.listen(15) # 设置监听 15表示服务端等待排队连接的最大数量
self.clients = [] # 用于存放客户端的响应信息
self.clients_name_ip = {} # 用与存放客户端名称与IP
self.get_conn() # 监听客户端连接
通过设置一个死循环, 让我们的服务端不断处于监听客户端的连接请求。一旦客户端发起一个连接请求,accept()方法会返回当前连接的客户端的socket连接对象和IP地址。
通过 print(cilent),可以看到:
<socket.socket fd=460, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.20.164', 8989), raddr=('192.168.20.164', 59239)>
此时,服务器会向客户端输入一条信息data,服务端需要将该信息编码encode,发送给客户端。同时,客户端接收到该信息后,需要将其节码,才能转为我们可以识别的内容。
def get_conn(self):
while True:
client, address = self.server.accept() # 等待接收连接请求
print("IP为{}的使用者正在请求连接。".format(address))
data = "与服务器链接成功,请输入昵称才可以聊天"
client.send(data.encode()) # server与client通信,send() decode
self.clients.append(client) # 链接用户添加到服务器的用户列表
Thread(target=self.get_msg, args=(client, self.clients,self.clients_name_ip, address)).start()
为将发送的名称与IP进行绑定,需要将客户端发送的用户名内容解码,追加到clients_name_ip参数中。此时,一旦客户端发来连接请求,并输入了昵称,那么昵称就会被解码存储在name变量中。
此时,服务端开始循环监听该客户端的消息。并且不断将客户端发来的消息进行解码。并将消息通过for循环的形式,重新编码发送给所有的客户端。
另外,如果检测到客户端发来的消息是一个"Q"字符,那么客户端就会被关闭。
def get_msg(self, client, clients, clients_name_ip, address):
name = client.recv(1024).decode() # 接受客户端发来的昵称
print("昵称:【{}】 设置成功".format(name))
clients_name_ip[address] = name # 昵称与IP进行绑定
while True: # 循环监听客户端消息
try:
recv_data = client.recv(1024).decode()
except Exception as e:
self.close_client(client, address)
break
# 入=如果用户输入Q,推出
if recv_data.upper() == "Q":
self.close_client(client, address)
break
for c in clients:
c.send((clients_name_ip[address] + " " + time.strftime("%x")+"\n"+recv_data).encode())
创建客户端的流程大致可以分为以下几个步骤:
1)创建客户端套接字(socket)对象
2)和服务器端套接字(socket)建立连接
3)发送数据
4)接受数据
5)关闭客户端套接字(socket)
客户端采用PyQT5,将客户端做成界面的形式进行交互。这里不对PyQT5做过多的解释。此处讲解使用的PyQT5比较简单,重点对服务端socket开发进行讲解。
首先,创建客户端socket对象,并连接服务器端口,并开启工作线程。
class Client(QWidget):
def __init__(self):
super(Client, self).__init__()
self.setGeometry(600, 300, 360, 300)
self.setWindowTitle("聊天室")
self.add_ui() # 界面UI,这个跟socket无关
self.client = socket.socket() # 与服务器链接
self.client.connect(("127.0.0.1", 8989))
self.work_thread() # 调用线程
发送消息通过的是用户点击发送按钮,点击发送按钮以后,QT会以信号的形式触发执行send_msg函数。至此,消息会被解码发送给服务器,如果检测到发送消息是字符‘Q’,那么客户端会被退出。
def btn_send(self): # 发送按钮点击,信号发射
self.button.clicked.connect(self.send_msg)
def send_msg(self): # 检测到发送按钮点击,该客户端就会向服务端发送数据
msg = self.message.text()
self.client.send(msg.encode())
if msg.upper() == "Q":
self.client.close()
self.destroy()
self.message.clear()
通过接收消息,将接收后的消息解码,通过append的形式追加到QT的控件中,用于在界面中显示
def recv_msg(self):
while True:
try:
data = self.client.recv(1024).decode()
print(data)
data = data + "\n"
self.content.append(data)
except:
exit()
通过调用该方法,来启动发送消息线程、接收消息线程。
def work_thread(self):
Thread(target=self.btn_send).start() # 发送消息
Thread(target=self.recv_msg).start()
第一步:启动服务器Server
第二步:启动一个Client (pycharm)
第三步:再启动一个Client (cmd)
(关注“测试开发自动化” 弓中皓,获取更多学习内容)