Python套接字文件传输

10

我试图编写通过套接字传输文件或数据块的代码。尽管感觉自己在重新发明轮子,但我还是找不到简单解决方案(所有我找到的东西要么太简单要么太复杂)。服务器将在运行Python 2.5.4的手机上运行。目标应用程序是在手机和主机计算机之间同步音乐文件。

这是我的核心代码,看起来似乎可以工作。我发送和接收“ok”以分隔流。

发送“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')

Uhh... - Ignacio Vazquez-Abrams
好的想法,但是在手机上运行HTTP服务器效果相当糟糕。 - foosion
5个回答

4

发送“ok”来回传递,以打破数据流的停止位技术是否合理?

大多数协议使用某种终止符。流行的替代方案是“\r\n”,“\r\n\r\n”或EOF(ctrl + d),但这些只是任意选择,与您的“ok”一样好或更好,只要客户端和服务器知道如何处理它。


2

你的代码看起来不错。

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

while True:
    data = s.recv(1024)

    if not data: print " Done "; break

    recvd += data

另外,如果对方不检查“ok”,为什么要发送“ok”?这只是在双方每次都跳过2个字节。

您是否需要迎合多个客户端?不需要使用多线程吗?


1

1
你可以看一下这个实现方式。它也会处理文件是否在子目录中的情况。这里是链接服务器
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

0

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接