Python struct.error:struct格式的字符不正确

Python struct.error:struct格式的字符不正确,python,struct,char,Python,Struct,Char,在Python2.7中,我有一个服务器-客户机分配的小问题 客户端可以向服务器发送5种类型的请求: 获取服务器的ip地址 获取服务器上目录的内容 在服务器上运行cmd命令并获取输出 在服务器上打开计算器 断开 基本上,这是我得到的错误: line 19, in server data_size = calcsize(client_structs) - 3 struct.error: bad char in struct format 如果您能解释一下这个错误,以及如何解决它,我们将不

在Python2.7中,我有一个服务器-客户机分配的小问题

客户端可以向服务器发送5种类型的请求:

  • 获取服务器的ip地址
  • 获取服务器上目录的内容
  • 在服务器上运行cmd命令并获取输出
  • 在服务器上打开计算器
  • 断开
  • 基本上,这是我得到的错误:

    line 19, in server
        data_size = calcsize(client_structs) - 3
    
    struct.error: bad char in struct format
    
    如果您能解释一下这个错误,以及如何解决它,我们将不胜感激

    服务器代码:

    __author__ = 'eyal'
    
    from struct import pack, unpack, calcsize
    import socket
    from os import listdir
    from subprocess import check_output, call
    
    
    def server():
        ser_soc = socket.socket()
        ser_soc.bind(("0.0.0.0", 8080))
        ser_soc.listen(1)
        while True:
            accept_flag = raw_input("Would you like to wait for a client? (y/n) ")
            if accept_flag == "y":
                client_soc, client_address = ser_soc.accept()
                while True:
                    client_structs = client_soc.recv(1024)
                    data_size = calcsize(client_structs) - 3
                    data_str = 'c' * data_size
                    unpacked_data = unpack("BH" + data_str, client_structs)
                    if unpacked_data[0] == 1:
                        ip = socket.gethostbyname(socket.gethostname())
                        ip_data = 'c' * len(ip)
                        to_send = pack("BH" + str(len(ip)) + ip_data, unpacked_data[0], len(ip), ip)
                    elif unpacked_data[0] == 2:
                        content = listdir(str(unpacked_data[2]))
                        content_str = "\r\n".join(content)
                        content_data = 'c' * len(content_str)
                        to_send = pack("BH" + str(len(content_str)) + content_data, unpacked_data[0],
                                       len(content_str), content_str)
                    elif unpacked_data[0] == 3:
                        command = str(unpacked_data[2:]).split()
                        output = check_output(command)
                        message_data = 'c' * len(output)
                        to_send = pack("BH" + message_data, unpacked_data[0], len(output), output)
                    elif unpacked_data[0] == 4:
                        call("gnome-calculator")
                        msg_data = 'c' * len("The calculator is open.")
                        to_send = pack("BH" + msg_data, unpacked_data[0], len("The calculator is open."),
                                       "The calculator is open.")
                    elif unpacked_data[0] == 5:
                        client_soc.close()
                        break
                    else:
                        to_send = pack("BH" + 'c' * len("invalid message type, try again"),
                                       unpacked_data[0], len("invalid message type, try again"),
                                       "invalid message type, try again")
                    if unpacked_data[0] != 5:
                        client_soc.send(to_send)
            else:
                break
        ser_soc.close()
    
    
    def main():
        server()
    
    
    if __name__ == "__main__":
        main()
    
    客户端代码:

    __author__ = 'eyal'
    
    
    from struct import pack, unpack, calcsize
    import socket
    
    
    def client():
        my_soc = socket.socket()
        my_soc.connect(("127.0.0.1", 8080))
        while True:
            send_flag = raw_input("Would you like to send the server a request? (y/n) ")
            if send_flag == "y":
                msg_code = input("What type of request would you like to send?\n"
                                 "1. Get the server's IP address.\n"
                                 "2. Get content of a directory on the server.\n"
                                 "3. Run a terminal command on the server and get the output.\n"
                                 "4. Open a calculator on the server.\n"
                                 "5. Disconnect from the server.\n"
                                 "Your choice: ")
                if msg_code == 1 or msg_code == 4 or msg_code == 5:
                    to_send = pack("BH", msg_code, 0)
                elif msg_code == 2:
                    path = raw_input("Enter path of wanted directory to get content of: ")
                    to_send = pack("BH" + 'c' * len(path), msg_code, len(path), path)
                elif msg_code == 3:
                    command = raw_input("Enter the wanted terminal command, including arguments: ")
                    to_send = pack("BH" + 'c' * len(command), msg_code, len(command), command)
                else:
                    print "Invalid message code, try again\n"
    
                if 1 <= msg_code <= 5:
                    my_soc.send(to_send)
            else:
                break
        data = my_soc.recv(1024)
        unpacked_data = unpack("BH" + 'c' * (calcsize(data) - 3), data)
        print "The server's response to your type-" + str(msg_code) + " request:"
        print unpacked_data[2]
        my_soc.close()
    
    
    def main():
        client()
    
    
    if __name__ == "__main__":
        main()
    
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    从结构导入包、解包、计算
    导入套接字
    def client():
    my_soc=socket.socket()
    my_soc.connect(((“127.0.0.1”,8080))
    尽管如此:
    send_flag=原始输入(“是否向服务器发送请求?(y/n)”)
    如果发送标志=“y”:
    msg_code=input(“您希望发送什么类型的请求?\n”
    “1.获取服务器的IP地址。\n”
    “2.获取服务器上目录的内容。\n”
    “3.在服务器上运行终端命令并获取输出。\n”
    “4.在服务器上打开计算器。\n”
    “5.断开与服务器的连接。\n”
    “你的选择:”)
    如果msg_code==1或msg_code==4或msg_code==5:
    发送至=打包(“BH”,消息代码,0)
    elif msg_代码==2:
    path=raw\u输入(“输入要获取内容的所需目录的路径:”)
    to_send=pack(“BH”+“c”*len(路径),msg_代码,len(路径),路径)
    elif msg_代码==3:
    命令=原始输入(“输入所需的终端命令,包括参数:”)
    to_send=pack(“BH”+“c”*len(命令),msg_代码,len(命令),命令)
    其他:
    打印“无效的消息代码,请重试\n”
    如果1我认为问题在于:

    data_size = calcsize(client_structs) - 3
    
    客户端发送的数据似乎是任意二进制数据,而不是
    struct
    格式字符串。你不能打那个电话

    例如,如果我在客户机上选择
    1
    ,它会将消息代码
    1
    打包为一个字节,将数字
    0
    打包为一个短字符,因此它会发送
    b'\x01\x00\x00'
    。但在服务器上,您会收到它并尝试将其用作
    结构
    格式。因此,您会收到一个错误,指出
    b'\x01'
    不是有效的格式代码

    既然你给了我们一大堆不工作的代码,却没有解释它应该如何工作,很难猜测你应该在这里做什么,只是,不管你想做什么,这都不是办法

    看起来您的格式总是1字节代码,2字节长度,然后是一组与该长度匹配的任意字符。如果是这样的话,解析它的方法如下:

    code, length = unpack('BH', buffer[:3])
    other_stuff = unpack('c' * length, buffer[3:])
    
    虽然实际上,使用
    pack
    unpack
    来打包一串字节并没有多大意义;您只需返回已在
    缓冲区[3://code>中的相同内容,而在另一端,您只需将
    路径
    或任何其他内容打包到自身中

    总之,这只是一个猜测,因为我不知道您希望代码如何工作,所以这可能不是您希望它做的


    与此同时,你至少还有一个严重的问题需要解决。当您从客户端执行
    发送
    时,它可能会在服务器上的两个
    recv
    上显示为拆分,或与以前的
    发送
    合并。你不能只是
    recv
    而假设你有一条完整的消息

    这个问题最糟糕的地方是,当您在未加载的机器上使用localhost套接字进行测试时,它99.9999%的时间“工作”,这意味着您可能没有意识到您有问题。但是,一旦你试图在互联网上部署它,或者在你的机器忙的时候运行它,它就会开始到处失败,直到那时你才意识到,要调试这个问题,你必须编写大量的代码,并且经常重组整个程序


    您似乎设计了一个包含足够信息的协议,可以将消息从流中分离出来。但你必须实际做到这一点,而不仅仅是期待它像魔术一样发生。

    请给我们一个,而不是整个代码的转储。特别是,当它失败时,
    客户端结构中有什么?那个格式字符串是您期望的工作方式,还是您不知道为什么代码中的某个部分会生成格式字符串的意外部分并需要我们调试该部分的问题?同时,我不认为这是您的问题,但这是您需要解决的问题:。来自一侧的单个
    send
    可能会在另一侧显示为拆分为两个
    recv
    s,或者与另一个
    send
    合并在一起。所以你不能只做
    my_soc.recv(1024)
    ,然后假设你有一条消息。@abarnert问题是我不知道代码什么时候失败。当服务器收到客户机的messageSure时,异常回溯会告诉您这一点。但是,同样,当发生这种情况时,
    客户机结构中有什么?您希望在
    客户端结构中是什么?