我的代码中的错误是一个简单的ftp

时间:2016-10-28 04:46:04

标签: sockets python-2.6


在底部运行代码时遇到错误。它就像一个简单的ftp 我使用python2.6.6和CentOS版本6.8
在大多数Linux服务器中,它得到了正确的结果:(我很抱歉,我刚刚注册并且不能) 客户为例:

[root@Test ftp]# python client.py 
path:put|/home/aaa.txt

服务器:

[root@Test ftp]# python server.py 
connected...
pre_data:put|aaa.txt|4
cmd: put
file_name: aaa.txt
file_size: 4
upload successed.

但我在某些服务器上遇到错误(例如我自己的PC中的VM)。我做了很多测试(python2.6 / python2.7,Centos6.5 / Centos6.7),发现这个错误不是因为它们。这是错误信息:

[root@Lewis-VM ftp]# python server.py 
connected...
pre_data:put|aaa.txt|7sdfsdf           ###Here gets the wrong result, "sdfsdf" is the content of /home/aaa.txt  and it shouldn't be sent here to  'file_size' and so it  cause the "ValueError" below

cmd: put
file_name: aaa.txt
file_size: 7sdfsdf

----------------------------------------
Exception happened during processing of request from ('127.0.0.1', 10699)
Traceback (most recent call last):
  File "/usr/lib64/python2.6/SocketServer.py", line 570, in process_request_thread
    self.finish_request(request, client_address)
  File "/usr/lib64/python2.6/SocketServer.py", line 332, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/lib64/python2.6/SocketServer.py", line 627, in __init__
    self.handle()
  File "server.py", line 30, in handle
    if int(file_size)>recv_size:
ValueError: invalid literal for int() with base 10: '7sdfsdf\n'

还有什么,我发现如果我在client.py中的sk.send(cmd+"|"+file_name+'|'+str(file_size))sk.send(data)之间插入time.sleep(1),错误就会消失。我说我在不同的系统和python版本中进行了测试,错误不是因为它们。所以我想这是因为一些系统配置?我在python.org中检查了socket.send()和socket.recv(),但没有任何帮助。那么有人可以帮我解释为什么会这样吗?


代码在这里:

#!/usr/bin/env python
#coding:utf-8

################
#This is server#
################

import SocketServer
import os

class MyServer(SocketServer.BaseRequestHandler):
    def handle(self):
        base_path = '/home/ftp/file'
        conn = self.request
        print 'connected...'
        while True:
            #####receive pre_data: we should get data like 'put|/home/aaa|7'
            pre_data = conn.recv(1024)
            print 'pre_data:' + pre_data
            cmd,file_name,file_size = pre_data.split('|')
            print 'cmd: ' + cmd
            print 'file_name: '+ file_name
            print 'file_size: '+ file_size
            recv_size = 0
            file_dir = os.path.join(base_path,file_name)
            f = file(file_dir,'wb')
            Flag = True
            ####receive 1024bytes each time
            while Flag:
                if int(file_size)>recv_size:
                    data = conn.recv(1024)
                    recv_size+=len(data)
                else:
                    recv_size = 0
                    Flag = False
                    continue

                f.write(data)
            print 'upload successed.'
            f.close()

instance = SocketServer.ThreadingTCPServer(('127.0.0.1',9999),MyServer)
instance.serve_forever()


#!/usr/bin/env python
#coding:utf-8


################
#This is client#
################

import socket
import sys
import os

ip_port = ('127.0.0.1',9999)
sk = socket.socket()
sk.connect(ip_port)

while True:
    input = raw_input('path:')
    #####we should input like  'put|/home/aaa.txt'
    cmd,path = input.split('|')
    file_name = os.path.basename(path)
    file_size=os.stat(path).st_size
    sk.send(cmd+"|"+file_name+'|'+str(file_size))
    send_size = 0
    f= file(path,'rb')
    Flag = True
    #####read 1024 bytes and send it to server each time
    while Flag:
        if send_size + 1024 >file_size:
            data = f.read(file_size-send_size)
            Flag = False
        else:
            data = f.read(1024)
            send_size+=1024
        sk.send(data)
    f.close()

sk.close()

1 个答案:

答案 0 :(得分:0)

TCP是一个数据流。那就是问题所在。 TCP不需要保留消息边界。所以当客户端调用

之类的东西时
connection.send("0123456789")
connection.send("ABCDEFGHIJ")

然后是一个天真的服务器,如

while True;
    data = conn.recv(1024)
    print data + "_"

可以打印以下任何内容:

 0123456789_ABCDEFGHIJ_
 0123456789ABCDEFGHIJ_
 0_1_2_3_4_5_6_7_8_9_A_B_C_D_E_F_G_H_I_J_

服务器没有机会识别有多少发送客户端被调用,因为客户端的TCP堆栈只是将数据插入到流中,并且服务器必须能够处理在不同于客户端使用的缓冲区中接收的数据。 / p>

您的服务器必须包含用于分隔标头和数据的逻辑。所有基于TCP的应用程序协议都使用一种机制来识别应用程序级边界。例如,HTTP通过空行分隔标题和正文,并在单独的标题中通知主体长度。

当服务器在单独的缓冲区中收到带有命令,名称和大小的标头时,当客户端足够快并且将数据快速推送到流中并且服务器在一个块中读取标头和数据时,您的程序正常工作。 / p>