服务器/客户端应用程序和JSONDecodeError:未终止的字符串python

2024-09-27 09:33:35 发布

您现在位置:Python中文网/ 问答频道 /正文

我有异步套接字服务器文件和客户端文件。 当我向客户端发送类似“download filename.ex”的内容时,该客户端的代码会处理我的请求:

try:
    content = read(sp_data[-1]).decode('utf-8')
    print(content)
    msg = json.dumps({'file': sp_data[-1], 'command': data, 'content': content,
                                  'msg': f'[+] File {sp_data[-1]} has been successfully downloaded.'}).encode('utf-8')
except FileNotFoundError:
    msg = json.dumps({'msg': f'[-] File {sp_data[-1]} not found', 'command': data}).encode('utf-8')
    s.send(msg)

当客户端向socketserver发送一些数据时,此服务器的代码处理收到的消息:

def recv_message(client_socket):
    global messages
    data = json.loads(client_socket.recv(4096).decode('utf-8').strip()) ##Important here i got this error json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 67 (char 66)
    raddr = get_raddr(str(client_socket))
    raddr = f'{raddr[0]}:{raddr[1]}'
    message = f'From: {raddr}\nCommand: {data["command"]}\nOutput: \n\n{data["msg"]}'
    try:
        d = messages[raddr]
        d.append(message)
        messages[raddr] = d
    except KeyError:
        messages[raddr] = [message]
    except AttributeError:
        print(message, messages)
    if 'content' in data.keys(): ##Important
        print(data['content'])
        threading.Thread(target=create_file, args=(data['file'], data['content'],), daemon=False).start()

错误:

data = json.loads(client_socket.recv(4096).decode('utf-8').strip())
json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 67 (char 66)

但是上面的服务器代码在接收到来自第一个代码的消息时给了我这个错误(当我向客户端发送类似“download file.ex”的消息时,客户端将我的命令检测为它的特殊命令,执行第一个代码,向服务器发送json文件。但是如果我发送“dir”命令发送给客户端,它将像shell命令一样检测我的命令,将通过子进程运行命令,将结果发送回服务器,我不会得到任何错误。)


注意:我还减少了socketserver的代码。因此,我的代码中的某些内容可能工作得更糟。这个post-make下载功能的主要目标是工作。我也知道我的代码很大。我在文件中留下了“##重要”注释。您只能查看由这些注释定位的代码。
服务器

import selectors
import socket
import threading
import json
import base64
import shlex

selector = selectors.DefaultSelector()

connections = {}


def accept_conn(server_socket):
    sock, addr = server_socket.accept()
    connections[len(connections) + 1] = [sock, f'{addr[0]}:{addr[-1]}']
    selector.register(fileobj=sock, events=selectors.EVENT_READ, data=recv_message)


s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('localhost', 4444))
s.listen()
selector.register(fileobj=s, events=selectors.EVENT_READ, data=accept_conn)

messages = {}

##Important 
def create_file(file, content): #content - base64 string
    print(content)
    with open(file, 'wb') as f:
        f.write(base64.b64decode(content.encode('utf-8')))


def recv_message(client_socket):
    global messages
    data = json.loads(client_socket.recv(4096).decode('utf-8').strip()) ##Important here i got this error json.decoder.JSONDecodeError: Unterminated string starting at: line 1 column 67 (char 66)
    raddr = get_raddr(str(client_socket))
    raddr = f'{raddr[0]}:{raddr[1]}'
    message = f'From: {raddr}\nCommand: {data["command"]}\nOutput: \n\n{data["msg"]}'
    try:
        d = messages[raddr]
        d.append(message)
        messages[raddr] = d
    except KeyError:
        messages[raddr] = [message]
    except AttributeError:
        print(message, messages)
    if 'content' in data.keys(): ##Important
        print(data['content'])
        threading.Thread(target=create_file, args=(data['file'], data['content'],), daemon=False).start()


def get_raddr(string):
    '''Get raddr parameter from client socket'''
    raddr = string.replace('>', '')
    return eval(raddr[raddr.find('raddr')::].replace('raddr=', ''))


def is_manage_string(sub, string):
    tokens = shlex.split(string)
    try:
        if len(tokens) == 2 and tokens[0] == sub and str(int(tokens[-1])):
            return True, int(tokens[-1])
    except Exception as e:
        print(e)
    return False


manage_process = False


def manage():
    global manage_process
    while True:
        manage_process = False
        command = input('>>> ').strip()
        if command == 'list':
            try:
                for i in range(1, len(connections) + 1):
                    print(f'{i}\t{connections[i][-1]}')
            except KeyError:
                pass
            if len(connections) == 0:
                print('[-] There are not any connections')
        elif 'manage' in command:
            index = is_manage_string('manage', command)
            if index:
                index = index[-1]
            else:
                print('[-] Invalid command\nUse manage "number_of_connection"\nEx: manage 1')
                continue
            if index >= 1 and index <= len(connections):
                sock, addr = connections[index]
                print(addr)
                print(f'{addr} is used')
                while True: ##Important here i launch loop which send data to socket
                    manage_process = True
                    command = input('>>> ').strip()
                    if command == 'messages':
                        try:
                            if messages[addr] == list():
                                print()
                                continue
                        except KeyError:
                            pass
                        try:
                            print('\n\n'.join(messages[addr]))
                        except KeyError:
                            print()
                    elif command == 'message':
                        try:
                            print(messages[addr][-1])
                        except:
                            print()
                    elif command == 'clear_messages':
                        try:
                            if messages[addr]:
                                messages[addr] = []
                        except KeyError:
                            print('[-] There are not any messages for cleaning up')
                    elif command == 'leave':
                        print(f'Leaving connection {addr}')
                        break
                    elif command: ##Important if command hasn't been detected as my special command(leave, messages), it will be executed like shell command
                        try:
                            sock.send(command.encode('utf-8'))
                            print(
                                'Your input has not been detected as special command and will execute like shell command or like client special command(ex: download; see client file)')
                        except ConnectionResetError:
                            print("Connection has been lost, therefore shell commands can't be used")
                    else:
                        continue

            else:
                print('[-] Invalid number of connection')

        elif command:
            print('[-] Invalid command\nType "help" to see avalible commands')

##Important
def event_loop():
    while True:
        data = selector.select()
        for key, _ in data:
            try:
                key.data(key.fileobj)
            except ConnectionResetError:
                selector.unregister(key.fileobj)


##Important
threading.Thread(target=manage, daemon=True).start()
event_loop()


客户端

import socket
import subprocess
import shlex
import threading
import json
import base64


s = socket.socket()
s.connect(('localhost', 4444))


##Important
def read(file):
    with open(file, 'rb') as f:
        return base64.b64encode(f.read())


def runner(data):
    sp_data = shlex.split(data)
    try:
        print(sp_data)
        if len(sp_data) == 2 and sp_data[0] == 'download': ###Important here we create json object which will be send to socketserver
            try:
                content = read(sp_data[-1]).decode('utf-8')
                print(content)
                msg = json.dumps({'file': sp_data[-1], 'command': data, 'content': content,
                                  'msg': f'[+] File {sp_data[-1]} has been successfully downloaded.'}).encode('utf-8')
            except FileNotFoundError:
                msg = json.dumps({'msg': f'[-] File {sp_data[-1]} not found', 'command': data}).encode('utf-8')
            s.send(msg)
            return ''
    except Exception as e:
        print(e)
    command = subprocess.run(data, shell=True, encoding='cp866', text=True, capture_output=True)
    command = command.stderr if command.stderr else command.stdout
    command = json.dumps({'msg': command, 'command': data})
    s.send(command.encode('utf-8'))


while True:##Important
    data = s.recv(4096).decode('utf-8').strip()
    threading.Thread(target=runner, args=(data,)).start()



Tags: jsondataifmsgsocketcontentspcommand
2条回答

解决方案-使用这些功能:

def send_msg(sock, msg):
    # Prefix each message with a 4-byte length (network byte order)
    msg = struct.pack('>I', len(msg)) + msg
    sock.sendall(msg)

def recv_msg(sock):
    # Read message length and unpack it into an integer
    raw_msglen = recvall(sock, 4)
    if not raw_msglen:
        return None
    msglen = struct.unpack('>I', raw_msglen)[0]
    # Read the message data
    return recvall(sock, msglen)

def recvall(sock, n):
    # Helper function to recv n bytes or return None if EOF is hit
    data = bytearray()
    while len(data) < n:
        packet = sock.recv(n - len(data))
        if not packet:
            return None
        data.extend(packet)
    return data
import socket
import struct


class Socket(socket.socket):
    def __init__(self):
        self.sock = socket.socket()
        super().__init__(socket.AF_INET, socket.SOCK_STREAM)

    def send_msg(self, msg):
        # Prefix each message with a 4-byte length (network byte order)
        msg = struct.pack('>I', len(msg)) + msg
        self.sock.sendall(msg)

    def recv_msg(self):
        # Read message length and unpack it into an integer
        raw_msglen = self.recv_all(4)
        if not raw_msglen:
            return None
        msglen = struct.unpack('>I', raw_msglen)[0]
        # Read the message data
        return self.recv_all(msglen)

    def recv_all(self, n):
        data = bytearray()
        while len(data) < n:
            packet = self.sock.recv(n - len(data))
            if not packet:
                return None
            data.extend(packet)
        return data

我把你的代码改成了Socket类

相关问题 更多 >

    热门问题