笔者最近也捡了捡n多年前学过的一点python基础,接触了一些socket编程,也参考了一些其他大佬的博客。
看见一个比较有趣的题目:用socket制作一个聊天室,于是自己也试着做了一下。
参考博客:https://blog.csdn.net/exmlyshy/article/details/85320971
在我的代码中我参考了上述博客的思路(客户端的脚本基本没什么改动),然后我在服务端的代码中加入了聊天记录的功能(通过写入文件),另外还有显示在线用户的功能。
import socket
import time
# 创建UDP套接字
svrsocket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 绑定
svrsocket.bind(('',8080))
# 聊天室内用户,用字典存放,{(ip:port):用户名}
users = {}
def send_record(msg):
'''
接收一个字符串
打印并传递给write2file和broadcast
通过该方法可在服务器和用户上看见用户进入/离开聊天室以及用户聊天信息
同时将上述信息写入文件(通过write2file)
'''
print(msg)
write2file(msg)
broadcast(msg)
def write2file(string):
'''
接收一个字符串
可将字符串作为单独的一行追加到文件末尾
用于将聊天信息记录到文件中
'''
file = open('/root/python/chat_history.txt','a')
file.write(string+"\n")
file.close()
def broadcast(msg):
'''
在套接字中广播(给每个用户都发送msg)
把每个用户发送的信息都发送给其他用户
'''
# 遍历用户字典users
for address in users:
svrsocket.sendto(msg.encode(), address)
while True:
try:
# 从UDP套接字接收到信息
user_data, user_addr = svrsocket.recvfrom(1024)
# 新用户加入聊天室
if not user_addr in users:
# 该用户进入聊天室的msg
enter_msg = time.asctime() + "\n" + user_data.decode() + "进入聊天室..."
# 该用户进入聊天室,发送提示并记录到文件
send_record(enter_msg)
# 将该用户添加到用户字典users
users[user_addr] = user_data.decode('utf-8')
# 新用户进入聊天室,无需再判断user_data
continue
# 用户输入"--EXIT"退出聊天
if '--EXIT' in user_data.decode('utf-8'):
# 用户离开聊天室的msg
leave_msg = time.asctime() + "\n" + users[user_addr] + "离开了聊天室..."
# 用户字典删除该用户
users.pop(user_addr)
# 用户退出聊天室,发送提示并记录到文件
send_record(leave_msg)
# 用户输入"--USERLIST"请求聊天室内在线用户列表
elif '--USERLIST' in user_data.decode('utf-8'):
# 遍历存放用户的字典users
for user in users.keys():
# list_msg = username+ip+port
list_msg = (users[user]+': '+user[0]+":"+str(user[1])).encode()
# 单独发送给请求userlist的用户
svrsocket.sendto(list_msg,user_addr)
else:
# 聊天室内用户正常聊天
msg = time.asctime() + '\n' +user_data.decode('utf-8')
# 发送消息并记录
send_record(msg)
except ConnectionResetError:
print("ConnectionResetError")
import socket
import threading
def send(sock,addr):
'''
该函数接受一个套接字和一个元组(地址,端口)
可通过input()获取用户输入,将信息发送给套接字
'''
while True:
# 获取用户输入
string = input()
# 发送输入信息
message = name + ": " + string
sock.sendto(message.encode('utf-8'),addr)
# 用户输入exit退出聊天
if string == '--EXIT':
break
def recv(sock,addr):
'''
该函数接受一个套接字和一个元组(地址,端口)
可通过套接字接收服务端发过来的信息
'''
sock.sendto(name.encode('utf-8'),addr)
while True:
data = sock.recv(1024)
print(data.decode('utf-8'))
print('____WELCOME____\n'+'EXIT -> exits\nUSERLIST -> get users')
# 获取用户名
name = input('please input your name:')
# 建立套接字
socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# 服务器IP地址为192.168.218.17,端口设置为8080
server = ('192.168.218.17',8080)
# 多线程接收和发送
tr = threading.Thread(target=recv,args=(socket,server),daemon=True)
ts = threading.Thread(target=send,args=(socket,server))
tr.start()
ts.start()
ts.join()
socket.close()
可以从效果图看出来,用户输入的信息和用户们的聊天记录混在一起,确实很影响用户体验,而且在聊天的时候没有任何提示符、消息的时间刷得太多同样也很影响使用。
笔者水平有限,如有错误欢迎指正!侵权必删