qq客户端与服务端代码疑问
来源:4-10 基于tcp自定义第一个协议 - 模拟qq服务器和客户端 - 3

Sven1194218
2020-08-13
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()
3回答
-
bobby
2020-08-17
# server 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()
改成这样,不要用一个socket连接既处理http请求也处理tcp交互请求
00 -
Sven1194218
提问者
2020-08-16
#client import socket import threading import json client = socket.socket() client.connect(("127.0.0.1",8000)) user = "yangfeng" 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: try: json_data = client.recv(1024).decode("utf8") #尝试通过sock接收信息,如果sock已关闭则退出while循环 except: break 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) 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")) client.close() 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()
#server 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) msg_template = '''HTTP/1.1 200 OK <html> <head> <title>Build a website!</title> </head> <body> Hello world, this is a very simple HTML docmemts. </body> </html> ''' sock.send(msg_template.encode("utf8")) 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()
00 -
bobby
2020-08-15
能否把代码格式化一下 我在这边运行一下试试
00
相似问题