聊天室服务器
思想步骤:
- 建立 Server Socket 对象,等待客户端连接
- 接收客户端连接,并保存到连接池
- 建立客户端线程,等待接受消息
- 接收到消息后,转发给其他所有客户端
- 收到 ‘exit’ 数据后,关闭客户端连接,将连接对象从连接池删除
import socket
import threading
class ClientThread(threading.Thread):
def __init__(self, sock, addr, conn_pool, pool_lock):
super().__init__()
self.daemon = True
self.sock = sock
self.addr = addr
self.conn_pool = conn_pool
self.pool_lock = pool_lock
def broadcast(self, msg):
'''广播'''
for addr, sock in self.conn_pool.items():
if addr != self.addr: # 排除自己
sock.send(msg) # 给其他人发消息
def exit(self):
'''退出'''
self.sock.close()
with self.pool_lock:
self.conn_pool.pop(self.addr)
def run(self):
'''线程的主函数'''
while True:
msg = self.sock.recv(1024)
if msg in [b'exit', b'']:
self.exit()
break
else:
self.broadcast(msg)
def main():
'''主程序'''
addr = ('0.0.0.0', 8000) # 服务器地址
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(addr)
sock.listen(1024)
print('服务器开始监听: %s:%s' % addr)
# 连接池对象
conn_pool = {}
pool_lock = threading.Lock()
while True:
cli_sock, cli_addr = sock.accept()
print('收到客户端连接: %s:%s' % cli_addr)
with pool_lock:
conn_pool[cli_addr] = cli_sock # 将 cli_sock 放入连接池
cli_thread = ClientThread(cli_sock, cli_addr, conn_pool, pool_lock)
cli_thread.start()
if __name__ == "__main__":
main()
聊天室客户端
思想步骤:
- 建立与服务器的连接
- 建立接收线程:收到消息后自动打印
- 建立发送线程:等待用户数据, 用户输入完后,将消息发送到服务器
- 用户输入 ‘exit’ 后,将消息发到服务器,然后关闭连接,最后退出客户端
import sys
import socket
import threading
class RecvThread(threading.Thread):
'''消息接收线程'''
def __init__(self, sock):
super().__init__()
self.daemon = True
self.sock = sock
def run(self):
while True:
msg = self.sock.recv(1024)
print(msg.decode('utf-8'))
def main(host, port):
addr = (host, port)
sock = socket.socket()
sock.connect(addr) # 与服务器建立连接
# 创建并启动消息接收线程
recv_thread = RecvThread(sock)
recv_thread.start()
# 等待用户输入消息,并发送
while True:
msg = input('请输入: ')
msg = msg.encode('utf-8')
sock.send(msg)
if msg == b'exit':
sock.close()
break
if __name__ == "__main__":
try:
host = sys.argv[1]
port = int(sys.argv[2])
except (IndexError, TypeError):
print('请输入正确的参数')
main(host, port)
运行结果:
在local(2)中输入qwer,local(3)中能接受到,服务器发生改变。