Python源码示例:sendfile.sendfile()
示例1
def _import_sendfile():
# By default attempt to use os.sendfile introduced in Python 3.3:
# http://bugs.python.org/issue10882
# ...otherwise fallback on using third-party pysendfile module:
# https://github.com/giampaolo/pysendfile/
if os.name == 'posix':
try:
return os.sendfile # py >= 3.3
except AttributeError:
try:
import sendfile as sf
# dirty hack to detect whether old 1.2.4 version is installed
if hasattr(sf, 'has_sf_hdtr'):
raise ImportError
return sf.sendfile
except ImportError:
pass
示例2
def _use_sendfile(self, producer):
if not self.cmd_channel.use_sendfile:
debug("starting transfer not using sendfile(2) as per server "
"config", self)
return False
if not isinstance(producer, FileProducer):
debug("starting transfer not using sendfile(2) (directory "
"listing)", self)
return False
else:
if not hasattr(self.file_obj, "fileno"):
debug("starting transfer not using sendfile(2) %r has no "
"fileno() method" % self.file_obj, self)
return False
if not producer.type == 'i':
debug("starting transfer not using sendfile(2) (text file "
"transfer)", self)
return False
debug("starting transfer using sendfile()", self)
return True
示例3
def _import_sendfile():
# By default attempt to use os.sendfile introduced in Python 3.3:
# http://bugs.python.org/issue10882
# ...otherwise fallback on using third-party pysendfile module:
# https://github.com/giampaolo/pysendfile/
if os.name == 'posix':
try:
return os.sendfile # py >= 3.3
except AttributeError:
try:
import sendfile as sf
# dirty hack to detect whether old 1.2.4 version is installed
if hasattr(sf, 'has_sf_hdtr'):
raise ImportError
return sf.sendfile
except ImportError:
pass
示例4
def _import_sendfile():
# By default attempt to use os.sendfile introduced in Python 3.3:
# http://bugs.python.org/issue10882
# ...otherwise fallback on using third-party pysendfile module:
# https://github.com/giampaolo/pysendfile/
if os.name == 'posix':
try:
return os.sendfile # py >= 3.3
except AttributeError:
try:
import sendfile as sf
# dirty hack to detect whether old 1.2.4 version is installed
if hasattr(sf, 'has_sf_hdtr'):
raise ImportError
return sf.sendfile
except ImportError:
pass
return None
示例5
def get_repr_info(self, as_str=False, extra_info={}):
info = OrderedDict()
info['id'] = id(self)
info['addr'] = "%s:%s" % (self.remote_ip, self.remote_port)
if _is_ssl_sock(self.socket):
info['ssl'] = True
if self.username:
info['user'] = self.username
# If threads are involved sometimes "self" may be None (?!?).
dc = getattr(self, 'data_channel', None)
if dc is not None:
if _is_ssl_sock(dc.socket):
info['ssl-data'] = True
if dc.file_obj:
if self.data_channel.receive:
info['sending-file'] = dc.file_obj
if dc.use_sendfile():
info['use-sendfile(2)'] = True
else:
info['receiving-file'] = dc.file_obj
info['bytes-trans'] = dc.get_transmitted_bytes()
info.update(extra_info)
if as_str:
return ', '.join(['%s=%r' % (k, v) for (k, v) in info.items()])
return info
示例6
def sendfile_wrapper(sock, file, offset, nbytes=BUFFER_LEN, header="",
trailer=""):
"""A higher level wrapper representing how an application is
supposed to use sendfile().
"""
while 1:
try:
if SUPPORT_HEADER_TRAILER:
sent = sendfile.sendfile(sock, file, offset, nbytes, header,
trailer)
else:
sent = sendfile.sendfile(sock, file, offset, nbytes)
except OSError:
err = sys.exc_info()[1]
if err.errno == errno.EAGAIN: # retry
continue
raise
else:
assert sent <= nbytes, (sent, nbytes)
return sent
示例7
def test_header(self):
total_sent = 0
header = b("x") * 512
sent = sendfile.sendfile(self.sockno, self.fileno, 0,
header=header)
total_sent += sent
offset = BUFFER_LEN
while 1:
sent = sendfile_wrapper(self.sockno, self.fileno, offset)
if sent == 0:
break
offset += sent
total_sent += sent
expected_data = header + DATA
self.assertEqual(total_sent, len(expected_data))
self.client.close()
self.server.wait()
data = self.server.handler_instance.get_data()
self.assertEqual(len(data), len(expected_data))
self.assertEqual(hash(data), hash(expected_data))
示例8
def _import_sendfile():
# By default attempt to use os.sendfile introduced in Python 3.3:
# http://bugs.python.org/issue10882
# ...otherwise fallback on using third-party pysendfile module:
# https://github.com/giampaolo/pysendfile/
if os.name == 'posix':
try:
return os.sendfile # py >= 3.3
except AttributeError:
try:
import sendfile as sf
# dirty hack to detect whether old 1.2.4 version is installed
if hasattr(sf, 'has_sf_hdtr'):
raise ImportError
return sf.sendfile
except ImportError:
pass
return None
示例9
def get_repr_info(self, as_str=False, extra_info={}):
info = OrderedDict()
info['id'] = id(self)
info['addr'] = "%s:%s" % (self.remote_ip, self.remote_port)
if _is_ssl_sock(self.socket):
info['ssl'] = True
if self.username:
info['user'] = self.username
# If threads are involved sometimes "self" may be None (?!?).
dc = getattr(self, 'data_channel', None)
if dc is not None:
if _is_ssl_sock(dc.socket):
info['ssl-data'] = True
if dc.file_obj:
if self.data_channel.receive:
info['sending-file'] = dc.file_obj
if dc.use_sendfile():
info['use-sendfile(2)'] = True
else:
info['receiving-file'] = dc.file_obj
info['bytes-trans'] = dc.get_transmitted_bytes()
info.update(extra_info)
if as_str:
return ', '.join(['%s=%r' % (k, v) for (k, v) in info.items()])
return info
示例10
def get_file(request, slug, attachment_id=None, filename=None):
attachment = get_object_or_404(Attachment, file__endswith='%s%s' % (posixpath.sep, filename), page__slug=slug)
as_attachment = ((not imghdr.what(attachment.file.path) and 'embed' not in request.GET)
or 'as_attachment' in request.GET)
# ref https://github.com/johnsensible/django-sendfile
return sendfile(request, attachment.file.path,
attachment=as_attachment, attachment_filename=text_type(attachment))
示例11
def initiate_sendfile(self):
"""A wrapper around sendfile."""
try:
sent = sendfile(self._fileno, self._filefd, self._offset,
self.ac_out_buffer_size)
except OSError as err:
if err.errno in _ERRNOS_RETRY or err.errno == errno.EBUSY:
return
elif err.errno in _ERRNOS_DISCONNECTED:
self.handle_close()
else:
if self.tot_bytes_sent == 0:
logger.warning(
"sendfile() failed; falling back on using plain send")
raise _GiveUpOnSendfile
else:
raise
else:
if sent == 0:
# this signals the channel that the transfer is completed
self.discard_buffers()
self.handle_close()
else:
self._offset += sent
self.tot_bytes_sent += sent
# --- utility methods
示例12
def _use_sendfile(self, producer):
if isinstance(self.socket, SSL.Connection):
debug(
"starting transfer not using sendfile(2) (SSL connection)",
self)
return False
else:
return super(TLS_DTPHandler, self)._use_sendfile(producer)
示例13
def initiate_sendfile(self):
"""A wrapper around sendfile."""
try:
sent = sendfile(self._fileno, self._filefd, self._offset,
self.ac_out_buffer_size)
except OSError as err:
if err.errno in _ERRNOS_RETRY or err.errno == errno.EBUSY:
return
elif err.errno in _ERRNOS_DISCONNECTED:
self.handle_close()
else:
if self.tot_bytes_sent == 0:
logger.warning(
"sendfile() failed; falling back on using plain send")
raise _GiveUpOnSendfile
else:
raise
else:
if sent == 0:
# this signals the channel that the transfer is completed
self.discard_buffers()
self.handle_close()
else:
self._offset += sent
self.tot_bytes_sent += sent
# --- utility methods
示例14
def _use_sendfile(self, producer):
if isinstance(self.socket, SSL.Connection):
debug(
"starting transfer not using sendfile(2) (SSL connection)",
self)
return False
else:
return super(TLS_DTPHandler, self)._use_sendfile(producer)
示例15
def export_user_data(request: Request):
"""
Export all user data in a zip blob and serve it through sendfile.
"""
user = request.user
# Cleanup old archives.
cache_expiration = datetime.fromtimestamp(datetime.now().timestamp() - USER_EXPORT_DATA_CACHE_PERIOD)
for archive in UserArchive.objects.filter(owner=user,
updated_on__lte=cache_expiration).iterator():
try:
archive.local_archive.delete()
except ValueError:
pass
finally:
archive.delete()
try:
archive = UserArchive.objects.get(owner=user)
return sendfile(request, archive.local_archive.path)
except (UserArchive.DoesNotExist, OSError, IOError, ValueError):
try:
builder = UserDataArchiveBuilder(user)
export(builder)
archive, _ = UserArchive.objects.get_or_create(owner=user)
builder.archive.close() # save the ZIP file.
archive.local_archive.save('data.zip',
File(open(builder.archive_filename, 'rb')))
builder.cleanup()
return sendfile(request, archive.local_archive.path)
except (OSError, IOError, django.db.Error) as e:
print(e)
return Response({}, status=status.HTTP_503_SERVICE_UNAVAILABLE)
示例16
def get(self, request, pk):
try:
odlc = find_odlc(request, int(pk))
except Odlc.DoesNotExist:
return HttpResponseNotFound('Odlc %s not found' % pk)
except ValueError as e:
return HttpResponseForbidden(str(e))
if not odlc.thumbnail or not odlc.thumbnail.name:
return HttpResponseNotFound('Odlc %s has no image' % pk)
# Tell sendfile to serve the thumbnail.
return sendfile(request, odlc.thumbnail.path)
示例17
def initiate_sendfile(self):
"""A wrapper around sendfile."""
try:
sent = sendfile(self._fileno, self._filefd, self._offset,
self.ac_out_buffer_size)
except OSError as err:
if err.errno in _ERRNOS_RETRY or err.errno == errno.EBUSY:
return
elif err.errno in _ERRNOS_DISCONNECTED:
self.handle_close()
else:
if self.tot_bytes_sent == 0:
logger.warning(
"sendfile() failed; falling back on using plain send")
raise _GiveUpOnSendfile
else:
raise
else:
if sent == 0:
# this signals the channel that the transfer is completed
self.discard_buffers()
self.handle_close()
else:
self._offset += sent
self.tot_bytes_sent += sent
# --- utility methods
示例18
def initiate_sendfile(self):
"""A wrapper around sendfile."""
try:
sent = sendfile(self._fileno, self._filefd, self._offset,
self.ac_out_buffer_size)
except OSError, err:
if err.errno in (errno.EAGAIN, errno.EWOULDBLOCK, errno.EBUSY):
return
elif err.errno in _DISCONNECTED:
self.handle_close()
else:
raise
示例19
def get_export_result(request, api_key, hash_id):
job = Job.objects.get(hashid=hash_id)
try:
user_id = ApiKey.objects.get(key=api_key).user_id
assert user_id == job.user.id
except:
return HttpResponseForbidden("This user did not request that file!")
if job.status != "Complete":
return HttpResponseNotFound("Export is not complete")
filepath = settings.SENDFILE_ROOT + job.data
return sendfile(request, filepath, attachment=True)
示例20
def get(self, request, *args, **kwargs):
attachment = get_r_object_or_404(self.request.user, Attachment,
issue__project__name_short=self.kwargs.get('project'),
issue__number=self.kwargs.get('sqn_i'),
seqnum=self.kwargs.get('sqn_a'))
# TODO BUG For some reason this is reported as a leak of resources: there is an unclosed file,
# which has been opened with mode='rb' and closefd=True
# So I assume the development-backend doesn't close the file properly
return sendfile(request, attachment.file.path, attachment=True)
示例21
def test_trailer(self):
with open(TESTFN2, 'wb') as f:
f.write(b("abcde"))
with open(TESTFN2, 'rb') as f:
sendfile.sendfile(self.sockno, f.fileno(), 0,
trailer=b("12345"))
time.sleep(.1)
self.client.close()
self.server.wait()
data = self.server.handler_instance.get_data()
self.assertEqual(data, b("abcde12345"))
示例22
def test_send_nbytes_0(self):
# On Mac OS X and FreeBSD a value of 0 for nbytes
# is supposed to send the whole file in one shot.
# OSX implementation appears to be just broken.
# On *BSD this works most of the times: sometimes
# EAGAIN is returned internally and here we get the
# number of bytes sent.
sent = sendfile.sendfile(self.sockno, self.fileno, 0, 0)
if sent == len(DATA):
self.client.close()
self.server.wait()
data = self.server.handler_instance.get_data()
self.assertEqual(len(data), len(DATA))
self.assertEqual(hash(data), hash(DATA))
示例23
def test_flags(self):
try:
sendfile.sendfile(self.sockno, self.fileno, 0, BUFFER_LEN,
flags=sendfile.SF_NODISKIO)
except OSError:
err = sys.exc_info()[1]
if err.errno not in (errno.EBUSY, errno.EAGAIN):
raise
# --- corner cases
示例24
def test_offset_overflow(self):
# specify an offset > file size
offset = len(DATA) + BUFFER_LEN
sent = sendfile.sendfile(self.sockno, self.fileno, offset, BUFFER_LEN)
self.assertEqual(sent, 0)
self.client.close()
self.server.wait()
data = self.server.handler_instance.get_data()
self.assertEqual(data, b(''))
示例25
def test_invalid_offset(self):
try:
sendfile.sendfile(self.sockno, self.fileno, -1, BUFFER_LEN)
except OSError:
err = sys.exc_info()[1]
self.assertEqual(err.errno, errno.EINVAL)
else:
self.fail("exception not raised")
示例26
def test_offset_none(self):
# on Linux offset == None sendfile() call is supposed
# to update the file offset
while 1:
sent = sendfile_wrapper(self.sockno, self.fileno, None)
if sent == 0:
break
self.client.close()
self.server.wait()
data = self.server.handler_instance.get_data()
self.assertEqual(len(data), len(DATA))
self.assertEqual(hash(data), hash(DATA))
示例27
def initiate_sendfile(self):
"""A wrapper around sendfile."""
try:
sent = sendfile(self._fileno, self._filefd, self._offset,
self.ac_out_buffer_size)
except OSError as err:
if err.errno in _ERRNOS_RETRY or err.errno == errno.EBUSY:
return
elif err.errno in _ERRNOS_DISCONNECTED:
self.handle_close()
else:
if self.tot_bytes_sent == 0:
logger.warning(
"sendfile() failed; falling back on using plain send")
raise _GiveUpOnSendfile
else:
raise
else:
if sent == 0:
# this signals the channel that the transfer is completed
self.discard_buffers()
self.handle_close()
else:
self._offset += sent
self.tot_bytes_sent += sent
# --- utility methods
示例28
def start_server(use_sendfile, keep_sending=False):
"""A simple test server which sends a file once a client connects.
use_sendfile decides whether using sendfile() or plain send().
If keep_sending is True restart sending file when EOF is reached.
"""
sock = socket.socket()
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((HOST, PORT))
sock.listen(1)
conn, addr = sock.accept()
sock.close()
file = open(BIGFILE, 'rb')
def on_exit(signum, fram):
file.close()
conn.close()
sys.exit(0)
signal.signal(signal.SIGTERM, on_exit)
signal.signal(signal.SIGINT, on_exit)
if not use_sendfile:
while 1:
chunk = file.read(BUFFER_SIZE)
if not chunk:
# EOF
if keep_sending:
file.seek(0)
continue
else:
break
conn.sendall(chunk)
else:
offset = 0
sockno = conn.fileno()
fileno = file.fileno()
while 1:
try:
sent = sendfile(sockno, fileno, offset, BUFFER_SIZE)
except OSError:
err = sys.exc_info()[1]
if err.errno in (errno.EAGAIN, errno.EBUSY):
continue
raise
else:
if not sent:
# EOF
if keep_sending:
offset = 0
continue
else:
break
else:
offset += sent
示例29
def main():
parser = optparse.OptionParser()
parser.add_option('-k', '--keepfile', action="store_true", default=False,
help="do not remove test file on exit")
options, args = parser.parse_args()
if not options.keepfile:
atexit.register(lambda: safe_remove(BIGFILE))
if not os.path.exists(BIGFILE) or os.path.getsize(BIGFILE) < BIGFILE_SIZE:
print_("creating big file...")
create_file(BIGFILE, BIGFILE_SIZE)
print_("starting benchmark...")
# CPU time: use sendfile()
server = Process(target=start_server, kwargs={"use_sendfile": True})
server.start()
time.sleep(0.1)
t1 = timeit.Timer(setup="from __main__ import Client; client = Client()",
stmt="client.retr()").timeit(number=1)
server.terminate()
server.join()
# CPU time: use send()
server = Process(target=start_server, kwargs={"use_sendfile": False})
server.start()
time.sleep(0.1)
t2 = timeit.Timer(setup="from __main__ import Client; client = Client()",
stmt="client.retr()").timeit(number=1)
server.terminate()
server.join()
# MB/sec: use sendfile()
server = Process(target=start_server, kwargs={"use_sendfile": True,
"keep_sending": True})
server.start()
time.sleep(0.1)
client = Client()
bytes1 = client.retr_for_1_sec()
server.terminate()
server.join()
# MB/sec: use sendfile()
server = Process(target=start_server, kwargs={"use_sendfile": False,
"keep_sending": True})
server.start()
time.sleep(0.1)
client = Client()
bytes2 = client.retr_for_1_sec()
server.terminate()
server.join()
print_(" ")
print_("send()", hilite=True)
print_(" cpu: %7.2f usec/pass" % (1000000 * t2 / 100000))
print_(" rate: %7.2f MB/sec" % round(bytes2 / 1024.0 / 1024.0, 2))
print_("")
print_("sendfile()", hilite=True)
print_(" cpu: %7.2f usec/pass" % (1000000 * t1 / 100000))
print_(" rate: %7.2f MB/sec" % round(bytes1 / 1024.0 / 1024.0, 2))