<p>我假设您使用裸套接字进行此操作有一个特定的原因,例如自我启发,这意味着我不会回答“您不小心忘记了只使用HTTP和Twisted”,这也许您已经<a href="https://stackoverflow.com/questions/42356322/tcp-client-server-with-sockets-server-sending-files-to-clients-client-hangs-p/42448335">heard before</a>:-p了。但实际上,您应该在某个点上查看更高级别的库,因为它们要容易得多!</p>
<h3>定义协议</h3>
<p>如果您只想发送图像,那么它可以很简单:</p>
<ol>
<li><code>Client -> server: 8 bytes</code>:大端,图像长度。</li>
<li><code>Client -> server: length bytes</code>:所有图像数据。</li>
<li>(<code>Client <- server: 1 byte, value 0</code>:表示接收到传输-可选步骤您可能不在乎是否使用TCP,而只是假设它是可靠的。)</li>
</ol>
<h3>编码</h3>
<p>服务器.py</p>
<pre><code>import os
from socket import *
from struct import unpack
class ServerProtocol:
def __init__(self):
self.socket = None
self.output_dir = '.'
self.file_num = 1
def listen(self, server_ip, server_port):
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.bind((server_ip, server_port))
self.socket.listen(1)
def handle_images(self):
try:
while True:
(connection, addr) = self.socket.accept()
try:
bs = connection.recv(8)
(length,) = unpack('>Q', bs)
data = b''
while len(data) < length:
# doing it in batches is generally better than trying
# to do it all in one go, so I believe.
to_read = length - len(data)
data += connection.recv(
4096 if to_read > 4096 else to_read)
# send our 0 ack
assert len(b'\00') == 1
connection.sendall(b'\00')
finally:
connection.shutdown(SHUT_WR)
connection.close()
with open(os.path.join(
self.output_dir, '%06d.jpg' % self.file_num), 'w'
) as fp:
fp.write(data)
self.file_num += 1
finally:
self.close()
def close(self):
self.socket.close()
self.socket = None
# could handle a bad ack here, but we'll assume it's fine.
if __name__ == '__main__':
sp = ServerProtocol()
sp.listen('127.0.0.1', 55555)
sp.handle_images()
</code></pre>
<p>客户端.py</p>
<pre><code>from socket import *
from struct import pack
class ClientProtocol:
def __init__(self):
self.socket = None
def connect(self, server_ip, server_port):
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.connect((server_ip, server_port))
def close(self):
self.socket.shutdown(SHUT_WR)
self.socket.close()
self.socket = None
def send_image(self, image_data):
# use struct to make sure we have a consistent endianness on the length
length = pack('>Q', len(image_data))
# sendall to make sure it blocks if there's back-pressure on the socket
self.socket.sendall(length)
self.socket.sendall(image_data)
ack = self.socket.recv(1)
# could handle a bad ack here, but we'll assume it's fine.
if __name__ == '__main__':
cp = ClientProtocol()
image_data = None
with open('IMG_0077.jpg', 'r') as fp:
image_data = fp.read()
assert(len(image_data))
cp.connect('127.0.0.1', 55555)
cp.send_image(image_data)
cp.close()
</code></pre>