python socket推送消息到客户端

背景

由于目前项目中没有使用到浏览器,所以从服务端推送消息到客户的重任到了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()

执行演示

python socket推送消息到客户端_第1张图片
python socket推送消息到客户端_第2张图片

参考

多线程编程:https://www.liaoxuefeng.com/wiki/1016959663602400/1017629247922688
python socket 编程参考:https://www.runoob.com/python/python-socket.html

你可能感兴趣的:(python,python,网络,tcp/ip)