gpt4 book ai didi

python - 在 Python 中通过套接字发送大量数据的正确方法是什么?

转载 作者:太空狗 更新时间:2023-10-29 16:56:31 24 4
gpt4 key购买 nike

最近我写了一些代码(客户端和服务器)来发送图像 - 客户端只需使用 socket 模块将图像上传到服务器:Sending image over sockets (ONLY) in Python, image can not be open .

不过,我现在关心的是图片发送部分。这是我使用的原始图像:

enter image description here

在我的服务器代码(接收图像)中,我有这些行:

myfile = open(basename % imgcounter, 'wb')
myfile.write(data)

data = sock.recv(40960000)
if not data:
myfile.close()
break
myfile.write(data)
myfile.close()

sock.sendall("GOT IMAGE")
sock.shutdown()

但我认为这不是最好的方法。我想我应该改为实现服务器,使其接收 block 中的数据:

#!/usr/bin/env python

import random
import socket, select
from time import gmtime, strftime
from random import randint

imgcounter = 1
basename = "image%s.png"

HOST = '127.0.0.1'
PORT = 2905

connected_clients_sockets = []

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)

connected_clients_sockets.append(server_socket)

while True:

read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], [])

for sock in read_sockets:

if sock == server_socket:

sockfd, client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)

else:
try:

data = sock.recv(4096)
txt = str(data)

if data:

if data.startswith('SIZE'):
tmp = txt.split()
size = int(tmp[1])

print 'got size %s' % size

sock.sendall("GOT SIZE")

elif data.startswith('BYE'):
sock.shutdown()

else :

myfile = open(basename % imgcounter, 'wb')
myfile.write(data)

amount_received = 0
while amount_received < size:
data = sock.recv(4096)
amount_received += len(data)

print amount_received

if not data:
break
myfile.write(data)
myfile.close()

sock.sendall("GOT IMAGE")
sock.shutdown()
except:
sock.close()
connected_clients_sockets.remove(sock)
continue
imgcounter += 1
server_socket.close()

但是当我这样做时,服务器打印:

got size 54674
4096
8192
12288
16384
20480
24576
28672
32768
36864
40960
45056
49152
50578

然后好像挂了,客户端也挂了。然而,在服务器端我只能看到客户端想要发送的图像的一部分:

enter image description here

似乎缺少一些字节。仅使用套接字发送大量数据(图像、其他类型的文件)的正确方法是什么?

最佳答案

我假设您有特殊原因使用裸套接字执行此操作,例如 self 教育,这意味着我不会回答说“您不小心忘记了只使用 HTTP 和 Twisted”,这也许你有heard before :-P。但实际上您应该在某个时候查看更高级别的库,因为它们要容易得多!

定义协议(protocol)

如果你只想发送一张图片,那么它可以很简单:

  1. Client -> server: 8 bytes : 大端,图像长度。
  2. Client -> server: length bytes : 所有图像数据。
  3. ( Client <- server: 1 byte, value 0 :表示接收到传输 - 可选步骤,您可能不关心您是否使用 TCP,只是假设它是可靠的。)

编码

服务器.py

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()

客户端.py

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()

关于python - 在 Python 中通过套接字发送大量数据的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42459499/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com