struct.error:结构格式的坏字符 [英] struct.error: bad char in struct format

查看:2251
本文介绍了struct.error:结构格式的坏字符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在python 2.7中有一个服务器 - 客户端分配的问题。



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


  1. 获取服务器的ip

  2. 获取服务器上的目录内容


  3. 在服务器上运行cmd命令并获取输出
  4. 在服务器上打开计算器
  5. ol>

    基本上,这是我得到的错误:

     第19行server 
    data_size = calcsize(client_structs) - 3

    struct.error:结构格式的错误字符

    感谢您解释此错误+如何解决。



    服务器代码:


    $ b b

      __ author__ ='eyal'

    来自struct import pack,unpack,calcsize
    import socket
    从os import listdir
    从子进程import check_output,调用


    def server():
    ser_soc = socket.socket()
    ser_soc.bind((0.0.0.0 ,8080))
    ser_soc.listen(1)
    while True:
    accept_flag = raw_input(你想等待客户端吗? (y / n))
    如果accept_flag ==y:
    client_soc,client_address = ser_soc.accept()
    while True:
    client_structs = client_soc.recv )
    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 )+ ip_data,unpacked_data [0],len(ip),ip)
    elif unpacked_data [0] == 2:
    content = listdir(str(unpacked_data [2]))
    content_str =\r\\\
    .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 $ b 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(计算器打开)
    to_send = pack (BH+ msg_data,unpacked_data [0],len(计算器打开。),
    计算器打开。)
    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),
    无效的消息类型,重试)
    如果unpacked_data [0]!= 5:
    client_soc.send (to_send)
    else:
    break
    ser_soc.close()


    def main():
    server b

    if __name__ ==__main__:
    main()

    客户代码:

      __ author__ ='eyal'


    pack,unpack,calcsize
    import socket


    def client():
    my_soc = socket.socket()
    my_soc.connect .0.1,8080))
    while True:
    send_flag = raw_input(你想向服务器发送请求吗? (y / n))
    如果send_flag ==y:
    msg_code = input(要发送什么类型的请求?\\\

    服务器的IP地址。\\\

    2.获取服务器上的目录的内容。\\\

    3.在服务器上运行terminal命令并获取输出。 n
    4.在服务器上打开一个计算器。\\\

    5.断开与服务器的连接。\\\

    您的选择:)
    如果msg_code == 1或者msg_code == 4或者msg_code == 5:
    to_send = pack(BH,msg_code,0)
    elif msg_code == 2:
    path = raw_input 输入想要的目录的路径以获取内容:)
    to_send = pack(BH+'c'* len(path),msg_code,len(path),path)
    elif msg_code = = 3:
    command = raw_input(输入想要的终端命令,包括参数:)
    to_send = pack(BH+'c'* len(command),msg_code,len ,command)
    else:
    print无效的消息代码,再试一次\\\

    $ b如果1 <= msg_code <= 5:
    ,$ my_soc。 send(to_send)
    else:
    break
    data = my_soc.recv(1024)
    unpacked_data = unpack(BH+'c'*(calcsize ),
    打印服务器对你的类型的响应+ str(msg_code)+request:
    print unpacked_data [2]
    my_soc.close()


    def main():
    client()


    如果__name__ ==__main__:
    main 问题是这样的:

      data_size = calcsize(client_structs) -  3 

    客户端发送的数据似乎是任意的二进制数据,而不是 struct 格式字符串。您无法调用 calcsize

    例如,如果我在客户端上选择 1 将消息代码 1 作为一个字节,并将数字 0 作为短整, b'\x01\x00\x00'。但在服务器上,你收到并尝试使用它作为 struct 格式。所以,你得到一个错误,说 b'\x01'不是有效的格式代码。



    你已经给了我们大量的非工作代码,没有解释它应该如何工作,很难猜到你应该在这里做什么,只是,无论你想要什么,这个不能是这样做的。



    看起来你的格式总是一个1字节的代码,一个2字节的长度,然后一堆任意匹配该长度的字符。如果是这样,解析的方式将是这样:

      code,length = unpack('BH' :3])
    other_stuff = unpack('c'* length,buffer [3:])

    虽然确实没有太多意义,使用 pack unpack 你只需要回到已经在 buffer [3:] 中的相同的东西,另一方面你只是打包 path 或其他任何东西。



    无论如何,这只是一个猜测,因为我实际上不知道






    与此同时,您可以使用自己的代码,至少有一个其他严重的问题,你需要修复。 TCP套接字是字节流,而不是消息流< a>。当您从客户端执行发送时,它可能会显示在服务器上两个 recv 之间,或合并与之前的发送。你不能只是 recv ,并假设你有一条完整的消息。



    这个问题最糟糕的是,当你在没有负载的机器上使用localhost套接字测试时,它工作99.9999%的时间,这意味着你可能没有意识到你有问题。但是,一旦你尝试在互联网上部署它或运行它,当你的机器忙,它开始失败在所有的地方,只有那时你才意识到,要调试的问题,你必须写一个巨大的块代码,并且经常重组整个程序。



    您似乎设计了一个包含足够信息的协议,用于从流中分离消息。但你必须实际上 ,而不只是期望它发生像魔法。


    I have a problem with a little server-client assignment in python 2.7.

    The client can send 5 types of requests to the server:

    1. get the server's ip
    2. get contents of a directory on the server
    3. run cmd command on the server and get the output
    4. open a calculator on the server
    5. disconnect

    basically, this is the error I get:

    line 19, in server
        data_size = calcsize(client_structs) - 3
    
    struct.error: bad char in struct format
    

    Would appreciate explanation about this error + how to solve it.

    server code:

    __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()
    

    client code:

    __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()
    

    解决方案

    I think the problem is this:

    data_size = calcsize(client_structs) - 3
    

    The data the client sends over appears to be arbitrary binary data, not a struct format string. You can't call calcsize on that.

    For example, if I select 1 on the client, it will pack the message code, 1, as a byte, and the number 0 as a short, so it'll send the b'\x01\x00\x00'. But on the server, you receive that and try to use it as a struct format. So, you get an error saying that b'\x01' is not a valid format code.

    Since you've given us a ton of non-working code with no explanation of how it's supposed to work, it's hard to guess what you should be doing here, only that, whatever it is you want, this can't be the way to do it.

    It looks like your format is always a 1-byte code, a 2-byte length, and then a bunch of arbitrary characters matching that length. If so, the way to parse that would be something like this:

    code, length = unpack('BH', buffer[:3])
    other_stuff = unpack('c' * length, buffer[3:])
    

    Although really, there's not much point to using pack and unpack to pack a string of bytes; you're just going to get back the same thing that was already in buffer[3:], and on the other side you're just packing the path or whatever other thing it is into itself.

    Anyway, again, this is just a guess, because I don't actually know how you expected your code to work, so this may not be what you wanted it to do.


    Meanwhile, you've got at least one other serious problem that you need to fix. TCP sockets are byte streams, not message streams. When you do a send from the client, it may show up split across two recvs on the server, or merged with a previous send. You can't just recv and assume you have an entire message.

    The worst thing about this problem is that when you're testing with localhost sockets on a machine that's not under load, it "works" 99.9999% of the time, meaning you may not realize you have a problem. But then, as soon as you try to deploy it on the internet or run it when your machine is busy, it starts failing all over the place, and only then do you realize that to debug the problem you have to write a huge chunk of code, and often restructure your whole program.

    You seem to have designed a protocol that contains enough information to split the messages off the stream. But you have to actually do that, not just expect it to happen like magic.

    这篇关于struct.error:结构格式的坏字符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆