問題描述
我在 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:
- 獲取服務器的ip
- 獲取服務器上目錄的內容
- 在服務器上運行 cmd 命令并獲取輸出
- 在服務器上打開一個計算器
- 斷開連接
基本上,這是我得到的錯誤:
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:])
雖然真的,使用 pack
和 unpack
來打包一串字節并沒有多大意義;你只是要取回已經在 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 recv
s 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:結構格式中的錯誤字符的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!