<p>这是一个新的答案,基于对前一个的评论。在</p>
<p>我们将使用一个TCP套接字,通过交替发送名称和内容来发送每个文件,如<a href="http://cr.yp.to/proto/netstrings.txt" rel="nofollow">netstrings</a>,每个文件都在一个大流中。在</p>
<p>我假设Python2.6,两边的文件系统使用相同的编码,并且您不需要很多并发客户机(但是您可能偶尔需要两个,例如,真实的客户机和一个测试人员)。我再次假设您有一个模块<code>filegenerator</code>,它的<code>generate()</code>方法注册到<code>inotify</code>,将通知排队,<code>yield</code>一个接一个。在</p>
<p>在客户端.py公司名称:</p>
<pre><code>import contextlib
import socket
import filegenerator
sock = socket.socket()
with contextlib.closing(sock):
sock.connect((HOST, 12345))
for filename in filegenerator.generate():
with open(filename, 'rb') as f:
contents = f.read()
buf = '{0}:{1},{2}:{3},'.format(len(filename), filename,
len(contents), contents)
sock.sendall(buf)
</code></pre>
<p>在服务器.py公司名称:</p>
^{pr2}$
<hr/>
<p>如果在Windows上需要200多个客户机,在linux和BSD(包括Mac)上需要100多个客户机,在不太好的平台上需要十几个客户机,那么您可能希望使用事件循环设计而不是线程设计,在linux上使用<code>epoll</code>,在BSD上使用<code>kqueue</code>,在Windows上使用IO完成端口。这是一个痛苦的过程,但幸运的是,有一些框架可以为您概括一切。两个流行的(也是非常不同的)选择是<a href="http://twistedmatrix.com" rel="nofollow">Twisted</a>和{a3}。在</p>
<p>尤其是<code>gevent</code>的一个优点是,您现在可以编写线程化代码,通过一些简单的更改,您可以将它变成像魔术一样基于事件的代码。在</p>
<p>另一方面,如果您最终想要基于事件的代码,那么最好从一开始就学习和使用一个框架,这样您就不必处理<code>accept</code>循环和{<cd9>}的所有繁琐工作,直到您得到完整的消息并干净地关闭等等,只需编写您关心的部分。毕竟,上面一半以上的代码基本上都是每个服务器共享的东西的样板,所以如果你不必编写它,何必费心呢?在</p>
<hr/>
<p>你在评论中说:</p>
<blockquote>
<p>Also the files are binary, so it's possible that I'll have problems if client encodings are diferent from server's.</p>
</blockquote>
<p>请注意,我以二进制模式(<code>'rb'</code>和<code>'wb'</code>)打开了每个文件,并有意选择了一个协议(netstring),该协议可以处理二进制字符串,而不必尝试将它们解释为字符,也不必将嵌入的NUL字符视为EOF或类似的东西。而且,当我使用<code>str.format</code>时,在python2.x中,它不会进行任何隐式编码,除非您给它提供<code>unicode</code>字符串或提供基于区域设置的格式类型,而这两种我都没有做。(请注意,在3.x中,您需要使用<code>bytes</code>而不是{<cd15>},这会改变一些代码。)</p>
<p>换句话说,客户机和服务器的编码不会进入它;您执行的二进制传输与FTP的I模式完全相同。在</p>
<hr/>
<p>但是,如果您想要相反的情况,为目标系统自动传输文本和重新编码呢?有三种简单的方法:</p>
<ol>
<li>发送客户端的编码(要么在顶部发送一次,要么每个文件一次),然后在服务器上,从客户端解码并重新编码到本地文件。在</li>
<li>在text/unicode模式下执行所有操作,甚至是套接字。这很傻,在2.x中也很难做到。在</li>
<li>定义一个有线编码,比如UTF-8。客户端负责对文件进行解码并编码为UTF-8进行发送;服务器负责在接收时解码UTF-8并对文件进行编码。在</li>
</ol>
<p>使用第三个选项,假设文件将使用默认的文件系统编码,更改后的客户端代码是:</p>
<pre><code>with io.open(filename, 'r', encoding=sys.getfilesystemencoding()) as f:
contents = f.read().encode('utf-8')
</code></pre>
<p>在服务器上:</p>
<pre><code>with io.open(filename, 'w', encoding=sys.getfilesystemencoding()) as f:
f.write(contents.decode('utf-8'))
</code></pre>
<p>默认情况下,<code>io.open</code>函数还使用通用换行符,因此客户机将把任何内容转换为Unix风格的换行符,而服务器将转换为它自己的本机换行符类型。在</p>
<p>注意,FTP的T模式实际上并不进行任何重新编码;它只进行换行转换(以及它的一个更有限的版本)。在</p>