需求分析:
聊天工具是CS程序,C是每一个客户端,S是服务端
服务应具有的功能:
- 启动服务,包括绑定地址和端口,监听
- 建立连接,能和多个客户端建立连接
- 接收不同用户的信息
- 分发,将接收的某个用户的信息转发到已连接的所有客户端
- 停止服务
- 记录连接的客户端
import logging
import socket
import threading
FORMAT = '%(asctime)s %(threadName)s %(message)s'
logging.basicConfig(format=FORMAT, level=logging.INFO)
class ChatServer:
def __init__(self,ip='127.0.0.1',port=9999):
self.sock = socket.socket()
self.addr = (ip,port)
self.event = threading.Event()
self.clients = {}
def start(self):
self.sock.bind(self.addr)
self.sock.listen()
threading.Thread(target=self._accept,name='accept').start()
def stop(self):
for c in self.clients.values():
c.close()
self.sock.close()
self.event.wait(3)
self.event.set()
def _accept(self):
while not self.event.is_set():
conn,client = self.sock.accept()
self.clients[client] = conn
threading.Thread(target=self._recv,args=(conn,client),name='recv').start()
def _recv(self,conn,client):
#接收到了数据,并分发
while not self.event.is_set():
try:
data = conn.recv(1024)
except Exception as e:
logging.info('Error: {}'.format(e))
data = b"quit"
data = data.decode()
logging.info(data)
#客户端通知,退出机制
if data == "quit":
logging.info("-------quit-------")
self.clients.pop(client)
logging.info("conn close : {}".format(conn))
conn.close()
break
msg = "ack {}".format(data)
for conn in self.clients.values():
conn.send(msg.encode())
if __name__=='__main__':
chat = ChatServer()
chat.start()
e = threading.Event()
def showthreads():
while not e.wait(5):
logging.info(threading.enumerate())
threading.Thread(target=showthreads, daemon=True).start()
while not e.wait(1):
cmd = input(">>> ").strip()
if cmd == "quit":
chat.stop()
e.wait(3)
break