我正在尝试通过TCP套接字发送和接收文件
有很多问题
1当客户端连接到服务器时。服务器不“打印客户端连接…”,但在使用命令后打印。
2当我在服务器上使用'put'命令时发生了一个错误套接字错误:[Errno 107]传输终结点未连接,但文件映像已上载到服务器。
三。当我在客户端使用'get'命令时。我无法继续使用其他命令。
4最后一个问题是客户端无法退出并从服务器中列出文件。它显示AttributeError:“module”对象没有属性“send”
服务器
import socket
import sys
import os
HOST = 'localhost'
PORT = 3820
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.bind((HOST, PORT))
socket.listen(1)
while (1):
conn, addr = socket.accept()
print 'Client connected ..'
reqCommand = conn.recv(2048)
print 'Client> %s' %(reqCommand)
if (reqCommand == 'quit'):
break
#list file on server
elif (reqCommand == 'lls'):
start_path = os.listdir('.') # server directory
for path,dirs,files in os.walk(start_path):
for filename in files:
print os.path.join(filename)
else:
string = reqCommand.split(' ', 1) #in case of 'put' and 'get' method
reqFile = string[1]
if (string[0] == 'put'):
with open(reqFile, 'wb') as file_to_write:
while True:
data = socket.recv(1024)
# print data
if not data:
break
# print data
file_to_write.write(data)
file_to_write.close()
break
print 'Receive Successful'
elif (string[0] == 'get'):
with open(reqFile, 'rb') as file_to_send:
for data in file_to_send:
conn.sendall(data)
print 'Send Successful'
conn.close()
socket.close()
客户
^{pr2}$
除此之外,您还需要在传输协议中添加“帧”。当您在流套接字上执行
send
操作时,数据将被添加到一个缓冲区中,该缓冲区最终将被传递到另一端。然而,该缓冲器的大小是传送到另一侧的而不是。换句话说,假设您使用命令"put myfile.txt"
发送一个初始段。然后从myfile.txt
发送数据。现在因为您使用的是file object iterator(for data in file_to_send
),所以实际上一次只向它发送一行(可以说,对于文件传输协议,读取和发送固定的块更有意义,但这也可以工作)。假设myfile.txt
的第一行是"The quick brown fox\n"
当服务器进行第一次接收时,它可以接收}或{}或{}命令以及整个文件内容。这是因为流协议(TCP)不为您维护消息边界。在
"put "
或{实际上,在第一次接收时,您可能只接收到
"put myfile.txt"
,但指望它是非常不明智的,因为这取决于发送和接收系统上各种因素的时间安排,而这些因素都超出了您的控制范围。在因此,有两种常见的处理方法:
在开始处添加一个长度,该长度描述命令和任何命令参数的大小(以便您知道要传输的实际文件数据在流中的何处开始)。(大多数二进制文件传输协议都是这样工作的)
在命令末尾添加一些已知的分隔符,例如
'\n'
。例如,HTTP就是这样工作的。同样地,你的接收端需要确保它在每一点上都读取所需的数据量,以便保存正在传输的文件的完整内容。在
这意味着您要么(a)小心地
recv
恰好是命令数据所需的字节数,然后单独处理文件内容,要么(b)recv
将初始数据块放入缓冲区,然后精确地分割出“command”所需的内容,并确保其余部分稍后将作为文件数据进行处理。选项(b)通常可以通过在套接字上构建一个file对象来实现(请参见socket.makefile
),然后使用file对象的readline
方法只获得第一行。在代码的其他问题:
行
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
是个非常糟糕的主意。您刚刚通过创建一个同名的变量隐藏了整个socket
模块。例如,如果您试图在下一行中再次引用socket.AF_INET
,您将得到异常AttributeError: '_socketobject' object has no attribute 'AF_INET'
。您应该给变量起其他名称,比如说socket1
,就像在客户端那样。在客户端,你有相反的问题。您试图使用socketobject方法,但是提供了
socket
模块对象。(这就是您得到AttributeError: 'module' object has no attribute 'send'
)您需要重新组织代码,以便像在put
和get
函数中那样,对已连接的套接字对象调用send
方法。出现错误
socket.error: [Errno 107] Transport endpoint is not connected
,因为您试图在侦听套接字上recv
,而不是连接的套接字(conn
,它由socket.accept
返回)。使用侦听套接字可以做的唯一事情是accept
新连接(或close
)。您应该使用
sendall
而不是send
来确保每个字节都被发送。一般来说,所有的数据也将与send
一起发送,但在某些情况下,这种情况不会发生。服务器中的文件接收循环以
while True:
开始,但始终是breaks
。因此,它只接收第一个数据块(最多1024个字节)。如果文件比这个大,你肯定会截短它。您的服务器文件列表函数(
lls
命令)不会将其输出发送回客户端,它只是printin把它放到服务器端的控制台上。(别忘了,您需要在发回的文件名之间提供某种分隔符,否则它们将全部串联成一个大字符串。)相关问题 更多 >
编程相关推荐