#!usr/bin/env python# -*- coding:utf-8 _*-"""@author:zhengxin@file: test_socket2.py@time: 2023年1月13日 14:19# @describe: 练习一: 写一个群聊程序需求分析:聊天工具是 CS 程序,C 是每一个客户端,S 是服务器端。服务器应该具有的功能∶1.启动服务,包括绑定地址和端口,监听2.建立连接,能和多个客户端建立连接3.接收不同用户的信息4.分发,将接收的某个用户的信息转发到已连接的所有客户端5.停止服务6.记录连接的客户端"""import datetimeimport socketimport threadingimport loggingFORMAT = "%(asctime)s %(threadName)s %(thread)d %(message)s"logging.basicConfig(format=FORMAT, level=logging.INFO)class ChatServer():def __init__(self, ip='0.0.0.0', port=9999):# def __init__(self, ip='127.0.0.1', port=9999):self.addr = (ip, port)self.sock = socket.socket()self.clients = {}self.event = threading.Event()def start(self):self.sock.bind(self.addr)# 服务启动self.sock.listen()# 启动线程threading.Thread(target=self.accept, name='accept').start()def accept(self):while not self.event.is_set():# 阻塞s, raddr = self.sock.accept()logging.info(s)logging.info(raddr)self.clients[raddr] = s# 启动线程threading.Thread(target=self.recv, name='recv', args=(s, )).start()def recv(self, sock: socket.socket): # 很多线程while not self.event.is_set():try:# 阻塞,bytesdata = sock.recv(1024)logging.info(data)except Exception as e:logging.error(e)data = b'quit'if data == b'quit':# sock.getpeername() 返回连接套接字的远程地址。返回值通常是元组(ipaddr, port)self.clients.pop(sock.getpeername())breakmsg = "ack{}. {} {}".format(sock.getpeername(),datetime.datetime.now().strftime("%Y/%m/%d-%H:%M:%s"),data.decode()).encode()# 单个发送# sock.send('ack {}'.format(data.decode()).encode())# 多个发送for s in self.clients.values():s.send(msg)def stop(self):""" 停止服务 """for s in self.clients.values():s.close()self.sock.close()self.event.set()if __name__ == '__main__':cs = ChatServer()cs.start()while True:cmd = input(">>>>>>")# 退出if cmd.strip() == 'quit':cs.stop()threading.Event.wait(3)breaklogging.info(threading.enumerate())
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。