请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

qq客户端与服务端代码疑问

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

3回答

bobby 2020-08-17 11:20:28
# 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交互请求

0 回复 有任何疑惑可以回复我~
提问者 Sven1194218 2020-08-16 19:46:17
#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()


0 回复 有任何疑惑可以回复我~
bobby 2020-08-15 17:27:01

能否把代码格式化一下 我在这边运行一下试试

0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信