Python socket 发送 EOF

17 投票
3 回答
22399 浏览
提问于 2025-04-16 04:33

我有一个简单的文件传输程序,一个套接字用来发送文件数据,另一个套接字用来接收这些数据并写入文件。

我需要在传输完成后,从接收端向发送端发送一个确认信息

接收端的代码如下:

s.accept()
f = s.makefile()
f.read(1024)

发送端的代码如下:

s.connect(('localhost',6090))
f = s.makefile()
f.write('abcd') 
f.flush()

这里出现了问题,因为“abcd”并不是1024字节,所以接收端会一直等待,直到收到1024字节的数据。
解决办法是关闭套接字,但由于我需要接收端的确认,所以我不能关闭套接字。
我该如何告诉接收端停止等待呢?我在想写一个EOF字符。
我在网上看到“\x04”是EOF,但这并不奏效。
另外,由于数据可能是二进制的,我不想使用readline()方法。

3 个回答

3

如果你打算通过管道发送任何二进制数据,其实不应该使用“EOF”标记。因为如果你的二进制数据里恰好包含了这个字节序列,那就麻烦了。虽然你可以通过“转义”来避免这个问题,但这就需要在发送和接收两端都进行检查,还要确保你转义的序列也能正常处理。

如果你是在做一个生产系统,建议你看看有没有现成的网络API可以使用,比如FTP、HTTP、SFTP等。

如果这是一个学校的项目或者小规模的项目,你需要做的是编写一个通信协议。最简单的方式可能是让发送方先发送一个二进制整数X(选择一个数据大小并保持一致),然后再发送X字节的二进制数据。接收方首先获取这个大小,然后只期待接收到这个数量的数据。记住,如果你需要发送的数据量超过了X能发送的大小,就需要把数据分成小块来发送。

还要考虑在传输过程中如果通信中断会发生什么。你可以在read()上设置超时,但如果超时后通信立即恢复,你需要优雅地处理这种情况(虽然根据系统的不同,丢弃所有数据也可能被认为是优雅的处理方式)。

4

在网络编程中,写入和读取数据的操作是分开的。你可以关闭一个用于写入的连接,但仍然保持用于读取的连接打开。

你可以查看这个链接了解更多信息:http://docs.python.org/library/socket.html#socket.socket.shutdown

另外,FTP(文件传输协议)使用了两个连接:一个用于传输数据,另一个用于“确认”信息。

如果你使用第二个连接来处理这些额外的信息,会让你更轻松。

7

设计一个协议(也就是客户端和服务器之间的约定),来规定如何发送消息。一个简单的方法是“第一个字节表示消息的长度,接下来就是消息内容”。下面是一个简单的例子:

客户端

Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from socket import *
>>> s=socket()
>>> s.connect(('localhost',5000))
>>> f=s.makefile()
>>> f.write('\x04abcd')
>>> f.flush()

服务器

Python 2.6.5 (r265:79096, Mar 19 2010, 21:48:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from socket import *
>>> s=socket()
>>> s.bind(('localhost',5000))
>>> s.listen(1)
>>> c,a=s.accept()
>>> f=c.makefile()
>>> length=ord(f.read(1))
>>> f.read(length)
'abcd'

撰写回答