0

我正在尝试通过套接字发送/接收数据。将字符串转换为整数值时出现此错误。这个整数值是文件名的长度。

Traceback (most recent call last):

File "C:\Users\Nitesh Rathi\Desktop\clientSocket.py", line 16, in <module>

buff = int(filesize)

ValueError: invalid literal for int() with base 10: ''

代码

发送方

from socket import *
import os


HOST = '192.168.1.7'
PORT = 9999
ADDRESS = (HOST, PORT)

soc = socket(AF_INET, SOCK_STREAM)
soc.bind(ADDRESS)
soc.listen(5)
print('listen for connection...')
conn, addr = soc.accept()
print('got connection from', addr)

filename = 'file1.txt'.encode('utf-8')
fl = len(filename)
fl = str(fl)
print('size of filename :', fl, 'bytes')

conn.send(fl.encode('utf-8'))
print('size of filename sent')
conn.send(filename)
print('filename sent')
filedata = 'this is file1 data'.encode('utf-8')
conn.sendall(filedata)
print('data sent')


conn.close()
soc.close()
print('socket closed')

接收方

from socket import *
import os


HOST = '192.168.1.7'
PORT = 9999
ADDRESS = (HOST, PORT)
PATH = "C:/Users/Nitesh Rathi/Desktop/RECV"

soc = socket(AF_INET, SOCK_STREAM)
soc.connect(ADDRESS)
print('connected to', ADDRESS)

while True:
    filesize = soc.recv(255).decode('utf-8')
    buff = int(filesize)
    print("size of filename: ", filesize, 'bytes')
    filename = soc.recv(buff).decode('utf-8')
    if not filename: break
    Path = os.path.join(PATH, filename)
    print(Path)
    file = open(Path, 'wb')
    filedata = soc.recv(1024)
    file.write(filedata)
    file.close()


soc.close()
print('socket closed')
print('data recvd')
4

1 回答 1

0

TCP 流套接字实现流协议,而不是消息协议,因此接收者必须事先知道它应该接收多少字节。

您的代码将文件名长度作为字符串发送,后跟长度,这是一个模棱两可的协议...例如,如果文件名是42beers.txt您的代码将写入流

0x31  '1'
0x31  '1'
0x34  '4'
0x32  '2'
0x62  'b'
0x65  'e'
0x65  'e'
0x72  'r'
0x73  's'
0x2e  '.'
0x74  't'
0x78  'x'
0x74  't'

读者如何知道长度何时结束以及文件名何时开始?

请注意,recv理论上第一次调用可能会得到公正1或可能会得到1142b(因为它是字节流通道,而不是消息通道)。

您得到的错误可能是由于第二种可能性。

例如,如果您的文件名长度从不超过 255 个字节,另一种可行的方法是写入一个字节来表示字符串的长度,然后是字符串......即

0x0B  11 (length of filename)
0x34  '4'
0x32  '2'
0x62  'b'
0x65  'e'
0x65  'e'
0x72  'r'
0x73  's'
0x2e  '.'
0x74  't'
0x78  'x'
0x74  't'

这样,接收者可以read(1)用来获取一个字节(长度),然后再做另一个read(sz)来获取文件名。

回顾一下recv,您可以从网络中收到迄今为止收到的任何内容,它可能少于发送者传递的内容,send也可能是作者多次send调用的一部分。如果您使用recv,那么您必须执行一个循环,该循环一直累积直到接收到数据(并且您必须知道这是多少,或者您必须使用诸如 CRLF 之类的分隔符,就像 http 在请求标头中所做的那样)。

于 2019-12-07T22:20:01.523 回答