Bobby老师好,我的环境是mac,python3.8.3
问题1:服务端代码:
import socket
import threading
from collections import defaultdict
import json
#维护用户链接:
online_users = defaultdict(dict)
#维护用户的历史消息
user_msg = defaultdict(list)
server = socket.socket()
server.bind((“0.0.0.0”,8000))
server.listen()
def handle_sock(sock,addr): #sock是用户与服务器之间建立的通道,通道参数,addr是地址参数,均由accept方法返回
while True:
data = sock.recv(1024)
json_data = json.loads(data.decode(“utf8”))
print(json_data)
action = json_data.get(“action”,"")
print(action)
if action ==“login”:
online_users[json_data[“user”]]=sock
sock.send(“登陆成功!”.encode(“utf8”))
elif action =="list_user":
all_users = [user for user,sock in online_users.items()] #列表推导式
sock.send(json.dumps(all_users).encode("utf8"))
elif action =="history_msg":
sock.send(json.dumps(user_msg.get(json_data["user"],[])).encode("utf8"))
elif action =="send_msg":
if json_data["to"] in online_users:
online_users[json_data["to"]].send(json.dumps(json_data).encode("utf8"))
else:
user_msg[json_data["to"]].append(json_data["data"])
elif action =="exit":
print(online_users)
del online_users[json_data["user"]]
print(online_users)
sock.send("已成功退出登陆".encode("utf8"))
while True:
sock,addr = server.accept()
#启动一个线程
client_thread = threading.Thread(target=handle_sock, args=(sock,addr))
client_thread.start()
这段服务端代码无论客户端代码怎么调整,只要接收到客户端exit操作,都会抛出异常“ raise JSONDecodeError(“Expecting value”, s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)“
问题2:
qq_client.py客户端处理“退出”的代码:
elif choice ==“2”:
#退出功能
exit_template = {
“action”: “exit”,
“user”: user
}
client.send(json.dumps(exit_template).encode(“utf8”))
client.close()
break
这段代码会把客户端的sock关闭,导致handle_receive线程实际上无法获取到服务端的exit发送的“成功退出登陆”字符串。于是我把客户端的client.close()方法调整到了handle_receive里,当接收到非json字符串的信息时,再运行client.close(),并退出循环。此时可以接收打印出“成功退出登陆”。 但连续运行 op_type3,获取在线用户列表却会抛出 套接字关闭 的异常。
import socket
import threading
import json
client = socket.socket()
client.connect((“127.0.0.1”,8000))
user = “tangyi”
login_template = {
“action”:“login”,
“user”:user
}
client.send(json.dumps(login_template).encode(“utf8”))
print(client.recv(1024).decode(“utf8”))
offline_msg_template = {
“action”:“history_msg”,
“user”:user
}
client.send(json.dumps(offline_msg_template).encode(“utf8”))
offline_msg = client.recv(1024).decode(“utf8”) #json字符串
print(“收到离线消息:{}”.format(json.loads(offline_msg)))
get_user_template = {
“action”:“list_user”
}
client.send(json.dumps(get_user_template).encode(“utf8”))
online_users = client.recv(1024).decode(“utf8”) #json字符串
online_users = json.loads(online_users)
print(“当前在线用户:{}”.format(online_users))
def handle_receive():
while True:
json_data = client.recv(1024).decode(“utf8”) #尝试通过sock接收信息,如果sock已关闭则退出while循环
try:
data = json.loads(json_data) # 尝试将json字符串解码为普通字符串,如果json_data不是json字符串格式则直接打印出来
msg = data["data"]
from_user = data["from"]
print("")
print("收到来自 {} 的消息:{}".format(from_user,msg))
except:
print("")
print(json_data)
client.close()
break
def handle_send():
while True:
choice = input(“请选择你需要的操作:{}”.format(“1.发送消息,2.退出,3.获取在线用户”))
if choice not in [“1”,“2”,“3”]:
print(“没有此项操作,请重新输入”)
elif choice =="1":
#发送消息功能
send_to = input("发送给谁: ")
msg = input("请输入发送的内容: ")
send_data_template = {
"action": "send_msg",
"to": send_to,
"from": user,
"data": msg
}
client.send(json.dumps(send_data_template).encode("utf8"))
elif choice =="2":
#退出功能
exit_template = {
"action": "exit",
"user": user
}
client.send(json.dumps(exit_template).encode("utf8"))
break
elif choice =="3":
#获取在线用户
list_user_template = {
"action": "list_user"
}
client.send(json.dumps(list_user_template).encode("utf8"))
if name == “main”:
client_send = threading.Thread(target=handle_send)
client_send.start()
client_receiver = threading.Thread(target=handle_receive)
client_receiver.start()