在生产环境下使用生成器像服务器传输大文件

废话不多说,直接上代码

  1 # -*- coding: utf-8 -*-
  2 # Created by richie at 2018/10/23
  3 import os
  4 import sys
  5
  6 _ver = sys.version_info
  7
  8 #: Python 2.x?
  9 is_py2 = (_ver[0] == 2)
 10
 11 #: Python 3.x?
 12 is_py3 = (_ver[0] == 3)
 13
 14 import httplib
 15 import string
 16 import random
 17 from array import array
 18 from urllib3.exceptions import LocationParseError
 19 from urllib3.util import parse_url
 20
 21 if is_py2:
 22     from collections import Mapping
 23
 24     range = xrange
 25 elif is_py3:
 26     from collections.abc import Mapping
 27
 28     range = range
 29
 30 _BOUNDARY_CHARS = string.digits + string.ascii_letters
 31
 32
 33 def to_key_val_list(value):
 34     if value is None:
 35         return None
 36
 37     if isinstance(value, (str, bytes, bool, int)):
 38         raise ValueError(‘cannot encode objects that are not 2-tuples‘)
 39
 40     if isinstance(value, Mapping):
 41         value = value.items()
 42
 43     return list(value)
 44
 45
 46 class HTTPConnection(httplib.HTTPConnection):
 47     """
 48     改写send方法  使之能够接受生成器
 49     """
 50     def __enter__(self):
 51         return self
 52
 53     def __exit__(self, *args):
 54         self.close()
 55
 56     def send(self, data):
 57         """Send `data‘ to the server."""
 58         if self.sock is None:
 59             if self.auto_open:
 60                 self.connect()
 61             else:
 62                 raise httplib.NotConnected()
 63
 64         if self.debuglevel > 0:
 65             print "send:", repr(data)
 66         blocksize = 8192
 67         if hasattr(data, ‘next‘):
 68             for value in data:
 69                 self.sock.sendall(value)
 70
 71         elif hasattr(data, ‘read‘) and not isinstance(data, array):
 72             if self.debuglevel > 0: print "sendIng a read()able"
 73             datablock = data.read(blocksize)
 74             while datablock:
 75                 self.sock.sendall(datablock)
 76                 datablock = data.read(blocksize)
 77         else:
 78             self.sock.sendall(data)
 79
 80
 81 class Request(object):
 82
 83     def __init__(self, method=None, url=None, data=None, files=None, ):
 84         # Default empty dicts for dict params.
 85         data = [] if data is None else data
 86         files = [] if files is None else files
 87
 88         self.method = method
 89         self.url = url
 90         self.files = files
 91         self.data = data
 92         self.headers = {
 93             ‘Accept‘: ‘*/*‘,
 94             ‘Connection‘: ‘keep-alive‘,
 95         }
 96         self.__boundary = None
 97         self.__item_header = []
 98         self.end_tag = None
 99
100         self.init_body()
101
102     def __repr__(self):
103         return ‘<Request [%s]>‘ % (self.method)
104
105     def get_boundary(self):
106         if self.__boundary is None:
107             self.__boundary = ‘‘.join(random.choice(_BOUNDARY_CHARS) for _ in range(32))
108         return self.__boundary
109
110     def init_body(self):
111         """
112         组装数据
113         :return:
114         """
115         def escape_quote(s):
116             return s.replace(‘"‘, ‘\\"‘)
117
118         fields = to_key_val_list(self.data or {})
119         files = to_key_val_list(self.files or {})
120         lines = []
121         fpaths = []
122         fheads = []
123         if fields:
124             for name, value in fields:
125                 lines.extend((
126                     ‘--{0}‘.format(self.get_boundary()),
127                     ‘Content-Disposition: form-data; name="{0}"‘.format(escape_quote(name)),
128                     ‘‘,
129                     str(value),
130                 ))
131         if files:
132             __temp = []
133             for name, value in files:
134                 filename = os.path.basename(value)
135                 filename = filename.encode(‘utf-8‘)
136                 __temp.extend((
137                     ‘--{0}‘.format(self.get_boundary()),
138                     ‘Content-Disposition: form-data; name="{0}"; filename="{1}"‘.format(
139                         escape_quote(name), escape_quote(filename)),
140                     ‘\r\n‘,
141                 ))
142                 fpaths.append(value)
143                 fheads.append(‘\r\n‘.join(__temp))
144         fields_heads = ‘\r\n‘.join(lines) + ‘\r\n‘
145         self.end_tag = "--" + self.get_boundary() + "--\r\n"
146
147         content_type = str(‘multipart/form-data; boundary=%s‘ % self.get_boundary())
148         if content_type and (‘content-type‘ not in self.headers):
149             self.headers[‘Content-Type‘] = content_type
150
151         self.prepare_content_length(fields_heads, fheads, fpaths)
152         self.data = self.prepare_data(fields_heads, fheads, fpaths)
153
154     def prepare_data(self, fields_heads, fheads, fpaths):
155         """
156         通过生成器发送数据
157         :param fields_heads:
158         :param fheads:
159         :param fpaths:
160         :return:
161         """
162         b_size = 4096
163         yield fields_heads
164         for i in range(len(fheads)):
165             yield fheads[i]
166             file_obj = open(fpaths[i], ‘rb‘)
167             while True:
168                 block = file_obj.read(b_size)
169                 if block:
170                     yield block
171                 else:
172                     yield ‘\r\n‘
173                     break
174             yield self.end_tag
175
176     def prepare_content_length(self, fields_heads, fheads=None, fpaths=None):
177         """
178         准备发送内容的大小
179         :param fields_heads:
180         :param fheads:
181         :param fpaths:
182         :return:
183         """
184         if fields_heads is not None:
185             length = len(fields_heads)
186             if fpaths:
187                 for fpath in fpaths:
188                     length += os.path.getsize(fpath) + len(‘\r\n‘)  # file length
189                 for fhead in fheads:
190                     length += len(fhead)
191                 length += len(self.end_tag)
192             if length:
193                 self.headers[‘Content-Length‘] = str(length)
194
195         elif self.method not in (‘GET‘, ‘HEAD‘) and self.headers.get(‘Content-Length‘) is None:
196             self.headers[‘Content-Length‘] = ‘0‘
197
198     def send(self):
199         """
200         通过httplib发送请求
201         :return:
202         """
203         # Support for unicode domain names and paths.
204         try:
205             scheme, auth, host, port, path, query, fragment = parse_url(self.url)
206         except LocationParseError as e:
207             raise Exception(*e.args)
208
209         with HTTPConnection(host, port=port) as conn:
210             conn.request(self.method.upper(), self.url, self.data, self.headers)
211             # Receive the response from the server
212             try:
213                 # For Python 2.7, use buffering of HTTP responses
214                 response = conn.getresponse(buffering=True)
215             except TypeError:
216                 # For compatibility with Python 3.3+
217                 response = conn.getresponse()
218             status = response.status
219             content = response.read()
220         return status, content

原文地址:https://www.cnblogs.com/richiewlq/p/9916342.html

时间: 2024-10-17 03:31:46

在生产环境下使用生成器像服务器传输大文件的相关文章

为N台linux服务器传输大文件

1.服务端与客户端建立公钥及私钥信任关系.服务端作为原始文件存储地,ansible主机.1.1. 在ansible主机上创建公钥.ssh-keygen -b 1024 -t rsa[[email protected] ~]# ssh-keygen -b 1024 -t rsaGenerating public/private rsa key pair. #提示正在生成rsa密钥对Enter file in which to save the key (/home/usrname/.ssh/id_

生产环境下ftp的迁移并构建高可用

说明:这是1个小项目就两台DELL的服务器,和一台IP SAN存储(DELL MD3200i).原来是4台小服务器,而且服务器太老了,经常有问题,这回相当于一次ftp的迁移,以前用的是proftp,这次换成了vsftp.数据量有2.5T. 拓扑很简单: 系统:CENTOS 6.4(64bit) 高可用软件:corosync+pacemaker host:ftp1 192.168.1.190 ftp2  192.168.1.191 stonith(ipmi):ftp1 192.168.1.180

生产环境下的iptables

生产环境下的iptables设置,这是我自己的一点总结,浅显之处望大家指出批评,共同学习. 我的局域网为192.168.1.0/24. 1.先清空所有规则 iptables -F iptables -X iptables -Z iptables -t nat -F iptables -t nat -X iptables -t nat -Z 设置默认规则前开发ssh(6123)端口 iptables -A INPUT -i eth0 -s 192.168.1.0/24 -p tcp --dport

[原]生产环境下的nginx.conf配置文件(多虚拟主机)

[原]生产环境下的nginx.conf配置文件(多虚拟主机) 2013-12-27阅读110 评论0 我的生产环境下的nginx.conf配置文件,做了虚拟主机设置的,大家可以根据需求更改,下载即可在自己的机器上使用了,本配置文件摘录自<构建高可用Linux服务器>(机械工业出版社),转载麻烦注明出处,谢谢,配置文件如下: user  www www;worker_processes 8;error_log  /data/logs/nginx_error.log  crit;pid      

EF 第三篇 生产环境下的数据迁移

前言 本文所谓数据迁移,直白点不如说成数据库升级.虽然大部分带服务器型的应用,所有客户端都是连到同一台服务器上,对这样的生产环境,数据库升级起来不是什么难事,用vs自带的Migration也好,执行sql脚本也好,都比较容易.然而在每家客户现场都要部署一台服务器的应用也不少,如果一家家手工地去升级数据库,那将是一个可怕的工作量.那么对于这样的环境要怎么做到自动升级数据库呢?相信大家也在网上搜了不少了EF关于生产环境下的数据迁移方案,然后99%搜到的都是使用vs自带的Migration命令方式迁移

生产环境下JAVA进程高CPU占用故障排查

问题描述:生产环境下的某台tomcat7服务器,在刚发布时的时候一切都很正常,在运行一段时间后就出现CPU占用很高的问题,基本上是负载一天比一天高. 问题分析:1,程序属于CPU密集型,和开发沟通过,排除此类情况.2,程序代码有问题,出现死循环,可能性极大. 问题解决:1,开发那边无法排查代码某个模块有问题,从日志上也无法分析得出.2,记得原来通过strace跟踪的方法解决了一台PHP服务器CPU占用高的问题,但是通过这种方法无效,经过google搜索,发现可以通过下面的方法进行解决,那就尝试下

Java生产环境下性能监控与调优详解

第1章 课程介绍(Java秒杀课程老师倾力打造)本章为大家介绍生产环境可能存在的问题和常用的性能监控工具,以及课程能学到什么,课程内容如何安排等,让大家对课程有个全貌的认识,从而更好的学习这门课程.1-1 为什么学习这门课程? 第2章 基于JDK命令行工具的监控本章带大家学习JDK的命令行监控工具的使用,包括jps.jinfo.jstat.jmap.jstack, 并结合MAT实战如何定位内存溢出,实战如何定位死循环和死锁.2-1 JVM的参数类型2-2 查看JVM运行时参数2-3 jstat查

SpringCloud从入门到进阶(四)——生产环境下Eureka的完全分布式部署

内容 由于前两节的内容我们知道,开启了preferIpAddress后,Eureka的伪分布式部署会提示replica不可用.这一节我们讲解如何在生产环境下部署完全分布式的Eureka集群,确保开启了preferIpAddress后replica的可用性. 版本 IDE:IDEA 2017.2.2 x64 JDK:1.8.0_171 manve:3.3.3 SpringBoot:1.5.9.RELEASE SpringCloud:Dalston.SR1 适合人群 Java开发人员 节点信息: 节

读生产环境下go语言最佳实践有感

最近看了一篇关于go产品开发最佳实践的文章,go-in-procution.作者总结了他们在用go开发过程中的很多实际经验,我们很多其实也用到了,鉴于此,这里就简单的写写读后感,后续我也争取能将这篇文章翻译出来.后面我用soundcloud来指代原作者. 开发环境 在soundcloud,每个人使用一个独立的GOPATH,并且在GOPATH直接按照go规定的代码路径方式clone代码. $ mkdir -p $GOPATH/src/github.com/soundcloud $ cd $GOPA