由于目前项目中没有使用到浏览器,所以从服务端推送消息到客户的重任到了tcp上,本博客讲了如何用python的socket编程实现服务端到客户端的消息推送。
服务端开两个端口7890和9999,7890负责连接客户端,9999负责连接触发端,客户端连接上后挂起等待消息,触发端触发后向所有连接的客户端发送消息。
连接服务端的7890端口,并且用循环接收和打印服务端推送的数据。客户端代码如下:
from socket import *
import time
def main():
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
server_ip = "127.0.0.1"
server_port = 7890
tcp_client_socket.connect((server_ip, server_port))
msg = "hello sever!"
start_time = time.time()
tcp_client_socket.send(msg.encode("utf-8"))
while True: # 死循环接受服务端推送的信息
recv_data = tcp_client_socket.recv(1024)
print("接收数据:", recv_data.decode("utf-8"))
print("花费时间:{}s".format(time.time()-start_time))
# 关闭套接字
tcp_client_socket.close()
if __name__ == "__main__":
main()
用于通知服务端对所有的客户端进行消息的通知,代码与客户端类似,如下:
from socket import *
import time
def main():
tcp_client_socket = socket(AF_INET, SOCK_STREAM)
server_ip = "127.0.0.1"
server_port = 9999
tcp_client_socket.connect((server_ip, server_port))
msg = "hello sever!"
start_time = time.time()
tcp_client_socket.send(msg.encode("utf-8"))
recv_data = tcp_client_socket.recv(1024)
print("接收数据:", recv_data.decode("utf-8"))
print("花费时间:{}s".format(time.time()-start_time))
# 关闭套接字
tcp_client_socket.close()
if __name__ == '__main__':
main()
开两个端口7890和9999,7890负责连接客户端,9999负责连接触发端。两个端口分别使用两个循环:client_loop和action_loop在线程中等待连接。创建RequestManager类用于对客户端和触发端的请求进行处理,
并且将客户端的请求的socket连接存储在self.client_sockets中,当处理触发端的请求时对所有存储的客户端socket连接推送信息。
服务端代码如下:
from socket import *
from threading import Thread
import time
class RequestManager:
"""
管理客户端socket连接和触发端socket连接的类
"""
def __init__(self):
self.client_sockets = []
def handle_request(self, client_socket, clientAddr):
"""
处理客户端请求的函数,在线程中执行
"""
self.client_sockets.append(client_socket)
recv_data = client_socket.recv(1024) # 接收1024个字节
msg = recv_data.decode("utf-8")
print("receive:", msg)
def handle_action(self, client_socket, clientAddr):
"""
处理触发端请求的函数,在线程中执行
"""
recv_data = client_socket.recv(1024) # 接收1024个字节
msg = recv_data.decode("utf-8")
print("action receive:", msg)
ret = "server get your action msg"
self.send_msg()
client_socket.send(ret.encode("utf-8"))
client_socket.close()
def close_connect(self):
"""
关闭所有的客户端连接
"""
for client_socket in self.client_sockets:
client_socket.close()
def send_msg(self):
"""
触发后发送信息给所有的客户端
"""
print("DEBUG self.client_sockets:", self.client_sockets, "连接数量:", len(self.client_sockets))
msg = "这是发给客户端的信息"
for client_socket in self.client_sockets:
try:
client_socket.send(msg.encode("utf-8"))
except ConnectionResetError as e:
# 若信息发送失败,去除该连接
print("ERROR ConnectionResetError:", e)
self.client_sockets.remove(client_socket)
def client_loop(manger):
"""
连接客户端的循环
"""
port = 7890
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
address = ('', port)
tcp_server_socket.bind(address)
tcp_server_socket.listen(128)
while True:
# 等待客户端的链接
print("DEBGU in client_loop")
client_socket, clientAddr = tcp_server_socket.accept()
Thread(target=manger.handle_request, args=(client_socket, clientAddr)).start()
tcp_server_socket.close()
def action_loop(manger):
"""
连接触发端的循环
"""
port = 9999
tcp_server_socket = socket(AF_INET, SOCK_STREAM)
address = ('', port)
tcp_server_socket.bind(address)
tcp_server_socket.listen(128)
while True:
# 等待触发请求
client_socket, clientAddr = tcp_server_socket.accept()
Thread(target=manger.handle_action, args=(client_socket, clientAddr)).start()
tcp_server_socket.close()
def main():
print("服务成功启动")
manger = RequestManager()
Thread(target=client_loop, args=(manger,)).start()
Thread(target=action_loop, args=(manger,)).start()
while True:
# 死循阻塞程序
time.sleep(5)
if __name__ == "__main__":
main()
多线程编程:https://www.liaoxuefeng.com/wiki/1016959663602400/1017629247922688
python socket 编程参考:https://www.runoob.com/python/python-socket.html