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

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

问题描述

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

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

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

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

  1. 获取服务器的ip
  2. 获取服务器上目录的内容
  3. 在服务器上运行 cmd 命令并获取输出
  4. 在服务器上打开一个计算器
  5. 断开连接

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

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.

服务器代码:

__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 = "
".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?
"
                             "1. Get the server's IP address.
"
                             "2. Get content of a directory on the server.
"
                             "3. Run a terminal command on the server and get the output.
"
                             "4. Open a calculator on the server.
"
                             "5. Disconnect from the server.
"
                             "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
"

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

推荐答案

认为问题是这样的:

data_size = calcsize(client_structs) - 3

客户端发送的数据似乎是任意二进制数据,而不是 struct 格式字符串.你不能调用 calcsize关于那个.

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

例如,如果我在客户端选择1,它将消息代码1打包为一个字节,数字0 的缩写,所以它会发送 b'x01x00x00'.但是在服务器上,您会收到它并尝试将其用作 struct 格式.因此,您会收到一条错误消息,指出 b'x01' 不是有效的格式代码.

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'x01x00x00'. 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.

看起来您的格式始终是一个 1 字节的代码、一个 2 字节的长度,然后是一堆与该长度匹配的任意字符.如果是这样,解析的方式是这样的:

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:])

虽然真的,使用 packunpack 来打包一串字节并没有多大意义;你只是要取回已经在 buffer[3:] 中的东西,而在另一边你只是打包 path 或其他任何东西事物本身.

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.

与此同时,您至少还有一个其他严重问题需要解决.TCP 套接字是字节流,而不是消息流.当您从客户端执行 send 时,它可能会显示为在服务器上拆分为两个 recv,或与之前的 send 合并.你不能只是 recv 并假设你有一个完整的消息.

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.

这个问题最糟糕的地方在于,当您在一台没有负载的机器上使用 localhost 套接字进行测试时,它有 99.9999% 的时间工作",这意味着您可能没有意识到自己有问题.但是,一旦你尝试在互联网上部署它或在你的机器忙时运行它,它就会开始到处失败,然后你才意识到要调试问题,你必须编写大量的代码,并经常重组整个程序.

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天全站免登陆