【问题标题】:python socket file transferpython套接字文件传输
【发布时间】:2011-10-13 18:57:26
【问题描述】:

我正在尝试通过套接字写入传输文件或数据块。我觉得我好像在重新发明轮子,但我对简单解决方案的搜索失败了(我发现的一切要么太简单,要么太复杂)。服务器将在运行 python 2.5.4 的手机上运行。预期的应用是在手机和主机之间同步音乐文件。

这是我所拥有的胆量,它似乎有效。我发送和接收“确定”以分解流。

基本上来回发送“ok”作为停止位来分解数据流是一种合理的技术吗?

有标准的方法吗?

鉴于手机内存和处理能力的限制,在手机上运行任何类型的库服务器(ftp、http)都不是一个有用的解决方案。

服务器:

import socket

c = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
c.bind(('', 1234))
c.listen(1)
s,a = c.accept()

while True:
    data = s.recv(1024)
    cmd = data[:data.find('\n')]

    if cmd == 'get':
        x, file_name, x = data.split('\n', 2)
        s.sendall('ok')
        with open(file_name, 'rb') as f:
            data = f.read()
        s.sendall('%16d' % len(data))
        s.sendall(data)
        s.recv(2)

    if cmd == 'end':
        s.close()
        c.close()
        break

客户:

import socket

s = socket.socket()
s.connect(('192.168.1.2', 1234))

def get_file(s, file_name):
    cmd = 'get\n%s\n' % (file_name)
    s.sendall(cmd)
    r = s.recv(2)
    size = int(s.recv(16))
    recvd = ''
    while size > len(recvd):
        data = s.recv(1024)
        if not data: 
            break
        recvd += data
    s.sendall('ok')
    return recvd

print get_file(s, 'file1')
print get_file(s, 'file2')
s.sendall('end\n')

【问题讨论】:

  • 好主意,但 http 服务器在手机上运行得相当糟糕。

标签: python sockets file-transfer


【解决方案1】:

本质上来回发送“ok”作为停止位来分解 数据流是一种合理的技术吗?

大多数协议都使用一些终结符或其他终结符。流行的替代方案是 '\r\n'、'\r\n\r\n' 或 EOF (ctrl+d),但这些只是随意选择的,不会比你的 'ok' 差或好,只要你的客户并且服务器知道如何处理它。

【讨论】:

    【解决方案2】:

    rsync 是在两台计算机之间同步文件的标准方式。您可以像 http://code.activestate.com/recipes/577518-rsync-algorithm/ 那样用 Python 编写它,或者您可以像 http://freshmeat.net/projects/pysync/ 这样包装 C 库,并进行一些调整,例如将 MD4 替换为 MD5。

    或者,如果您想在套接字级别执行此操作,您确实应该将 asynchat 与 asyncore 一起使用。这是一个用 asynchat http://pyftpdlib.googlecode.com/svn-history/r20/trunk/pyftpdlib/FTPServer.py 编写的 FTP 服务器,但你应该从阅读 http://www.doughellmann.com/PyMOTW/asynchat/ 开始。注意关于消息终止符的部分第 2 点。很多网络协议都会做这样奇怪的事情,即有时它们会发送和接收整行命令和响应,有时它们发送和接收任意数据块,前面是块中有多少字节的计数。您可以使用 asynchat 更轻松地处理这个问题,并且您的程序也可以更好地扩展。

    【讨论】:

      【解决方案3】:

      有标准的方法吗?

      是的。 http://www.faqs.org/rfcs/rfc959.html

      描述执行此操作的标准方法。

      这是一个实现:http://docs.python.org/library/ftplib.html

      【讨论】:

        【解决方案4】:

        您的代码看起来不错。

        您实际上不需要发送整个文件的大小。您可以使用while True,因为检查if not data: break 将停止循环。

        while True:
            data = s.recv(1024)
        
            if not data: print " Done "; break
        
            recvd += data
        

        另外,为什么你发送'ok'是对方不检查它?您只是在每边跳过 2 个字节。

        您不需要迎合多个客户吗?不需要多线程?

        【讨论】:

          【解决方案5】:

          你可以看看这个实现。它还负责处理文件是否位于子目录中。这是link

          服务器

          import socket
          import os
          
          print('Waiting for clinet to connect...')
          c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
          c.bind(('', 1234))
          c.listen(1)
          s, a = c.accept()
          
          print('Connected. Going to receive file.')
          s.sendall('getfilename')
          filename = s.recv(1024)
          if '/' in filename:
              dir = os.path.dirname(filename)
              try:
                  os.stat(dir)
              except:
                  print('Directory does not exist. Creating directory.')
                  os.mkdir(dir)
          f = open(filename, 'wb')
          print('Filename: ' + filename)
          
          while True:
              s.sendall('getfile')
              size = int(s.recv(16))
              print('Total size: ' + str(size))
              recvd = ''
              while size > len(recvd):
                  data = s.recv(1024)
                  if not data: 
                      break
                  recvd += data
                  f.write(data)
                  #print(len(recvd))
              break
          s.sendall('end')
          print('File received.')
          
          s.close()
          c.close()
          f.close()
          

          客户

          import socket
          import sys
          
          if len(sys.argv) > 1 :
              print('Trying to connect...')
              s = socket.socket()
              s.connect(('127.0.0.1', 1234))
          
              print('Connected. Wating for command.')
              while True:
                  cmd = s.recv(32)
          
                  if cmd == 'getfilename':
                      print('"getfilename" command received.')
                      s.sendall(sys.argv[1])
          
                  if cmd == 'getfile':
                      print('"getfile" command received. Going to send file.')
                      with open(sys.argv[1], 'rb') as f:
                          data = f.read()
                      s.sendall('%16d' % len(data))
                      s.sendall(data)
                      print('File transmission done.')
          
                  if cmd == 'end':
                      print('"end" command received. Teminate.')
                      break
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-03-06
            • 1970-01-01
            相关资源
            最近更新 更多