向服务器请求数据的五种技术

Ajax,在它*基本的层面,是一种与服务器通讯而不重载当前页面的方法,数据可从服务器获得或发送给服务器。有多种不同的方法构造这种通讯通道,每种方法都有自己的优势和限制。
有五种常用技术用于向服务器请求数据:
(1)XMLHttpRequest (XHR)
(2)动态脚本标签插入
(3)框架
(4)Comet
(5)多部分的XHR
在现代高性能JavaScript中使用的三种技术是XHR,动态脚本标签插入和多部分的XHR。使用Comet和iframe(作为数据传输技术)往往是*限情况,不在这里讨论。

 一、XMLHttpRequest
目前*常用的方法中,XMLHttpRequest(XHR)用来异步收发数据。所有现代浏览器都能够很好地支持它,而且能够精细地控制发送请求和数据接收。你可以向请求报文中添加任意的头信息和参数(包括GET和POST),并读取从服务器返回的头信息,以及响应文本自身。以下是使用示例:
var url = ‘/data.php’;
var params = [
‘id=934875’,
‘limit=20’
];
var req = new XMLHttpRequest();
req.onreadystatechange = function() {
if (req.readyState=== 4) {
var responseHeaders = req.getAllResponseHeaders();
var data = req.responseText;
}
}
req.open(‘GET’, url + ‘?’ + params.join(‘&’), true);
req.setRequestHeader(‘X-Requested-With’, ‘XMLHttpRequest’);
req.send(null);
此例显示了如何从URL请求数据,使用参数,以及如何读取响应报文和头信息。readyState等于4表示整个响应报文已经收并完可用于操作。
readyState等于3则表示此时正在与服务器交互,响应报文还在传输之中。这就是所谓的“流”,它是提高数据请求性能的强大工具:
req.onreadystatechange = function() {
if (req.readyState=== 3) {
var dataSoFar = req.responseText;

}
else if (req.readyState=== 4) {
var data = req.responseText;

}
}
由于XHR提供了高级别的控制,浏览器在上面增加了一些限制。你不能使用XHR从当前运行的代码域之外请求数据,而且老版本的IE 也不提供readyState3,它不支持流。从请求返回的数据像一个字符串或者一个XML对象那样对待,这意味着处理大量数据将相当缓慢。
尽管有这些缺点,XHR仍旧是*常用的请求数据技术,也是*强大的,它应当成为你的首选。
当使用XHR请求数据时,你可以选择POST 或GET。如果请求不改变服务器状态只是取回数据(又称作幂等动作)则使用GET。GET请求被缓冲起来,如果你多次提取相同的数据可提高性能。
只有当URL和参数的长度超过了2’048个字符时才使用POST提取数据。因为Internet Explorer限制URL的长度,过长将导致请求(参数)被截断。
 二、动态脚本标签插入
该技术克服了XHR的*大限制:它可以从不同域的服务器上获取数据。这是一种黑客技术,而不是实例化一个专用对象,你用JavaScript创建了一个新脚本标签,并将它的源属性设置为一个指向不同域的URL。
var scriptElement = document.createElement(‘script’);
scriptElement.src = ‘http://any-domain.com/javascript/lib.js’;
document.getElementsByTagName_r(‘head’)[0].appendChild(scriptElement);
但是动态脚本标签插入与XHR相比只提供更少的控制。你不能通过请求发送信息头。参数只能通过GET方法传递,不能用POST。你不能设置请求的超时或重试,实际上,你不需要知道它是否失败了。你必须等待所有数据返回之后才可以访问它们。你不能访问响应信息头或者像访问字符串那样访问整个响应报文。
*后一点非常重要。因为响应报文被用作脚本标签的源码,它必须是可执行的JavaScript。你不能使用裸XML,或者裸JSON,任何数据,无论什么格式,必须在一个回调函数之中被组装起来。
var scriptElement = document.createElement(‘script’);
scriptElement.src = ‘http://any-domain.com/javascript/lib.js’;
document.getElementsByTagName_r(‘head’)[0].appendChild(scriptElement);
function jsonCallback(jsonString) {
var data = (‘(‘ + jsonString + ‘)’);
}
在这个例子中,lib.js 文件将调用jsonCallback 函数组装数据:
jsonCallback({ “status”: 1, “colors”: [ “#fff”, “#000”, “#ff0000” ] });
尽管有这些限制,此技术仍然非常迅速。其响应结果是运行JavaScript,而不是作为字符串必须被进一步处理。正因为如此,它可能是客户端上获取并解析数据*快的方法。我们比较了动态脚本标签插入和XHR的性能,在本章后面JSON 一节中。
请小心使用这种技术从你不能直接控制的服务器上请求数据。JavaScript没有权限或访问控制的概念,所以你的页面上任何使用动态脚本标签插入的代码都可以完全控制整个页面。包括修改任何内容、将用户重定向到另一个站点,或跟踪他们在页面上的操作并将数据发送给第三方。使用外部来源的代码时务必非常小心。
 三、多部分XHR
多部分XHR(MXHR)允许你只用一个HTTP 请求就可以从服务器端获取多个资源。它通过将资源(可以是CSS 文件,HTML 片段,JavaScript代码,或base64 编码的图片)打包成一个由特定分隔符界定的大字符串,从服务器端发送到客户端。JavaScript代码处理此长字符串,根据它的媒体类型和其他“信息头”解析出每个资源。
让我们从头到尾跟随这个过程。首先,发送一个请求向服务器索取几个图像资源:
var req = new XMLHttpRequest();
req.open(‘GET’, ‘rollup_images.php’, true);
req.onreadystatechange = function() {
if (req.readyState== 4) {
splitImages(req.responseText);
}
};
req.send(null);
这是一个非常简单的请求。你向rollup_images.php 要求数据,一旦你收到返回结果,就将它交给函数splitImages处理。
下一步,服务器读取图片并将它们转换为字符串:
$images = array(‘kitten.jpg’, ‘sunset.jpg’, ‘baby.jpg’);
foreach ($images as $image) {
$image_fh = fopen($image, ‘r’);
$image_data = fread($image_fh, filesize($image));
fclose($image_fh);
$payloads[] = base64_encode($image_data);
}
$newline = chr(1);
echo implode($newline, $payloads);
这段PHP代码读取三个图片,并将它们转换成base64字符串。它们之间用一个简单的字符,UNICODE的1,连接起来,然后返回给客户端。
然后回到客户端,此数据由splitImage 函数处理:
function splitImages(imageString) {
var imageData = imageString.split(“\u0001”);
var imageElement;
for (var i = 0, len = imageData.length; i < len; i++) {
imageElement = document.createElement(‘img’);
imageElement.src = ‘data:image/jpeg;base64,’ + imageData[i];
document.getElementById(‘container’).appendChild(imageElement);
}
}
此函数将拼接而成的字符串分解为三段。每段用于创建一个图像元素,然后将图像元素插入页面中。图像不是从base64 转换成二进制,而是使用data:URL 并指定image/jpeg 媒体类型。
*终结果是:在一次HTTP 请求中向浏览器传入了三张图片。也可以传入20 张或100 张,响应报文会更大,但也只是一次HTTP 请求。它也可以扩展至其他类型的资源。JavaScript文件,CSS 文件,HTML片段,许多类型的图片都可以合并成一次响应。任何数据类型都可作为一个JavaScript处理的字符串被发送。下面的函数用于将JavaScript代码、CSS 样式表和图片转换为浏览器可用的资源:
function handleImageData(data, mimeType) {
var img = document.createElement(‘img’);
img.src = ‘data:’ + mimeType + ‘;base64,’ + data;
return img;
}
function handleCss(data) {
var style = document.createElement(‘style’);
style.type = ‘text/css’;
var node = document.createTextNode(data);
style.appendChild(node);
document.getElementsByTagName_r(‘head’)[0].appendChild(style);
}
function handleJavaScript(data) {
(data);
}
由于MXHR响应报文越来越大,有必要在每个资源收到时立刻处理,而不是等待整个响应报文接收完成。这可以通过监听readyState3 实现:
var req = new XMLHttpRequest();
var getLatestPacketInterval, lastLength = 0;
req.open(‘GET’, ‘rollup_images.php’, true);
req.onreadystatechange = readyStateHandler;
req.send(null);
function readyStateHandler{
if (req.readyState=== 3 && getLatestPacketInterval === null) {
getLatestPacketInterval = window.setInterval(function() {
getLatestPacket();
}, 15);
}
if (req.readyState=== 4) {
clearInterval(getLatestPacketInterval);
getLatestPacket();
}
}
function getLatestPacket() {
var length = req.responseText.length;
var packet = req.responseText.substring(lastLength, length);
processPacket(packet);
lastLength = length;
}
当readyState3*次发出时,启动了一个定时器。每隔15毫秒检查一次响应报文中的新数据。数据片段被收集起来直到发现一个分隔符,然后一切都作为一个完整的资源处理。以健壮的方式使用MXHR的代码很复杂但值得进一步研究。
使用此技术有一些缺点,其中*大的缺点是以此方法获得的资源不能被浏览器缓存。如果你使用MXHR获取一个特定的CSS 文件然后在下一个页面中正常加载它,它不在缓存中。因为整批资源是作为一个长字符串传输的,然后由JavaScript代码分割。由于没有办法用程序将文件放入浏览器缓存中,所以用这种方法获取的资源也无法存放在那里。
另一个缺点是:老版本的Internet Explorer不支持readyState3或data: URL。Internet Explorer 8两个都支持,但在Internet Explorer 6和7中必须设法变通。
尽管有这些缺点,但某些情况下MXHR仍然显著提高了整体页面的性能:网页包含许多其他地方不会用到的资源(所以不需要缓存),尤其是图片。
网站为每个页面使用了独一无二的打包的JavaScript或CSS文件以减少HTTP请求,因为它们对每个页面来说是独一的,所以不需要从缓存中读取,除非重新载入特定页面。
由于HTTP请求是Ajax中**端的瓶颈之一,减少其需求数量对整个页面性能有很大影响。尤其是当你将100个图片请求转化为一个MXHR请求时。Ad hoc 在现代浏览器上测试了大量图片,其结果显示出此技术比逐个请求快了4到10倍。
有时你不关心接收数据,而只要将数据发送给服务器。你可以发送用户的非私有信息以备日后分析,或者捕获所有脚本错误然后将有关细节发送给服务器进行记录和提示。当数据只需发送给服务器时,有两种广泛应用的技术:XHR和灯标。
 (1) XMLHttpRequest
虽然XHR主要用于从服务器获取数据,它也可以用来将数据发回。数据可以用GET或POST 方式发回,以及任意数量的HTTP 信息头。这给你很大灵活性。当你向服务器发回的数据量超过浏览器的*大URL长度时XHR特别有用。这种情况下,你可以用POST 方式发回数据:
var url = ‘/data.php’;
var params = [
‘id=934875’,
‘limit=20’
];
var req = new XMLHttpRequest();
req.onerror = function() {
// Error.
};
req.onreadystatechange = function() {
if (req.readyState== 4) {
// Success.
}
};
req.open(‘POST’, url, true);
req.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);
req.setRequestHeader(‘Content-Length’, params.length);
req.send(params.join(‘&’));
正如你在这个例子中看到的,如果失败了我们什么也不做。当我们用XHR捕获登陆用户统计信息时这么做通常没什么问题,但是,如果发送到服务器的是至关重要的数据,你可以添加代码在失败时重试:
function xhrPost(url, params, callback) {
var req = new XMLHttpRequest();
req.onerror = function() {
setTimeout(function() {
xhrPost(url, params, callback);
}, 1000);
};
req.onreadystatechange = function() {
if (req.readyState== 4) {
if (callback && typeof callback === ‘function’) {
callback();
}
}
};
req.open(‘POST’, url, true);
req.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded’);
req.setRequestHeader(‘Content-Length’, params.length);
req.send(params.join(‘&’));
}
当使用XHR将数据发回服务器时,它比使用GET要快。这是因为对少量数据而言,向服务器发送一个GET请求要占用一个单独的数据包。另一方面,一个POST至少发送两个数据包,一个用于信息头。另一个用于POST体。POST更适合于向服务器发送大量数据,即因为它不关心额外数据包的数量,又因为Internet Explorer 的URL长度限制,它不可能使用过长的GET请求。
 (2) 灯标
此技术与动态脚本标签插入非常类似。JavaScript用于创建一个新的Image 对象,将src 设置为服务器上一个脚本文件的URL。此URL 包含我们打算通过GET格式传回的键值对数据。注意并没有创建img 元素或者将它们插入到DOM 中。
var url = ‘/status_tracker.php’;
var params = [
‘step=2’,
‘time=1248027314’
];
(new Image()).src = url + ‘?’ + params.join(‘&’);
服务器取得此数据并保存下来,而不必向客户端返回什么,因此没有实际的图像显示。这是将信息发回服务器的*有效方法。其开销很小,而且任何服务器端错误都不会影响客户端。
简单的图像灯标意味着你所能做的受到限制。你不能发送POST 数据,所以你被URL 长度限制在一个相当小的字符数量上。你可以用非常有限的方法接收返回数据。可以监听Image 对象的load 事件,它可以告诉你服务器端是否成功接收了数据。你还可以检查服务器返回图片的宽度和高度(如果返回了一张图片)并用这些数字通知你服务器的状态。例如,宽度为1 表示“成功”,2 表示“重试”。
如果你不需要为此响应返回数据,那么你应当发送一个204 No Content 响应代码,无消息正文。它将阻止客户端继续等待永远不会到来的消息体:
var url = ‘/status_tracker.php’;
var params = [
‘step=2’,
‘time=1248027314’
];
var beacon = new Image();
beacon.src = url + ‘?’ + params.join(‘&’);
beacon.onload = function() {
if (this.width == 1) {
// Success.
}
else if (this.width == 2) {
// Failure; create another beacon and try again.
}
};
beacon.onerror = function() {
// Error; wait a bit, then create another beacon and try again.
};
灯标是向服务器回送数据*快和*有效的方法。服务器根本不需要发回任何响应正文,所以你不必担心客户端下载数据。唯一的缺点是接收到的响应类型是受限的。如果你需要向客户端返回大量数据,那么使用XHR。如果你只关心将数据发送到服务器端(可能需要*少的回复),那么使用图像灯标。

使用Python来做物联网

使用Python来做物联网,就是这么easy!

 

搭建整套物联网系统的方法有很多,*近四处捣鼓,使用python + 阿里云搭建一套*简单的物联系统,可以将单片机上的数据通过阿里云传输到PC端。 一、基本结构 先看架构图 框架.png 二、设备端接入 物联网终端是用的ESP32,是一款自带蓝牙和Wifi的单片机。利用它可以直接接入互联网,无需其他模块。当然你可以将现在流行的NB-Iot模块来联网,不过需要自己写一下驱动程序。我买的模块是支持micropython开发的,在淘宝上可以搜索到,用起来很方便。有时间我会补上这一块的初步教程。 ESP32模块.jpg Micropython是可以在低端硬件上运行的python,可以使用python语言直接操作IO 和MCU的外设比如UART、I2C等,用起来非常方便,不要搭建复杂的开发环境,也不需要学习寄存器配置。作为一个对传统MCU开发非常熟悉的硬件工程师来说,感觉操作起来非常简单。目前Micropython已经支持很多硬件了,应该用比较广泛的STM32部分系列也被支持。Micropython也已经支持很多常用的库,比如蓝牙,telnet,mqtt等。下面这个链接是micropython的中文论坛。 www.micropython.org.cn/bbs/forum.p… ESP32 通过wifi 接入互联网,使用mqtt协议接入阿里云,将温度数据上传至阿里云。在云端通过消息订阅可以直接查看温度信息。在PC端使用python调用MQTT协议,接入到阿里云。但是PC端和ESP32在阿里云上是两个不同的设备,需要通过阿里云来转发信息,这样PC就可以拿到ESP32上传的数据了。 ESP32 上的代码如下: from umqtt.simple import MQTTClient import usocket as socket import time import wifi

wifi.connect()

#Demo_01 ProductKey = “”#使用你自己的 ClientId = “1234|securemode=3,signmethod=hmacsha1|” DeviceName = “Demo_01” DeviceSecret = “**********************”#使用你自己的

strBroker = ProductKey + “.iot-as-mqtt.cn-shanghai.aliyuncs.com” Brokerport = 1883

user_name = “Demo_01&”#使用你自己的 user_password = “*************************************”#使用你自己的

print(“clientid:”,ClientId,” “,”Broker:”,strBroker,” “,”User Name:”,user_name,” “,”Password:”,user_password,” “)

def connect(): client = MQTTClient(client_id = ClientId,server= strBroker,port=Brokerport,user=user_name, password=user_password,keepalive=60) #please make sure keepalive value is not 0

有几点需要说明: 1.代码中的wifi.connect()函数需要自己编写,网上能搜到类似的,也可以打赏私信我所要源码。 2.阿里云物联网平台的接入需要进行三元组认证,会根据一定的规则生成登录名和密码,这个网上信息还是比较全面的。 3.向阿里云物联网平台发布消息的格式一定要按照代码中所写,网上很多代码,但是对这一块的描述都不清楚。 Micropython使用的umqtt.simple库,一定要设置keepalive时间,否则无法连接。这一点我是摸索了好久,*终通过查看库的源码才发现的问题。 三、云端设置 在云端建立一个高级产品,并创建两个设备,以供ESP32 和PC连接。 device.JPG 需要在产品中定义一下功能。 device_define.JPG 云端和设备端都建立好了之后,可以查看设备运行状态看到数据上传 云端数据查看.JPG 这是查看数据记录得到的结果 云端数据记录.JPG 当你看到正确的数据之后,就说明你的成功接入物联网并上传了数据。 接下来就是*重要的部分——设置是使用规则引擎来进行数据转发,将设备demo_01的数据转发到demo_02。这一步的语法很重要,虽然有官网有详细教程,但是当时还是搞了好久才完全正确。 规则查询语句: SELECT items.IndoorTemperature.value as IndoorTemperature FROM “/sys/use-your-productkey-here/Demo_01/thing/event/property/post” WHERE items.IndoorTemperature.value > 0 四、PC端接入 PC 端使用python模拟MQTT设备登陆阿里云订阅消息就行了,只要装好python很快就可以实现,网上也有很多代码。代码的很大一部分就是在做三元组认证,可以将这部分稍微修改一下来计算ESP32 登陆时所需的 PC端python代码如下: # coding=utf-8 import datetime import time import hmac import hashlib import math

try: import paho.mqtt.client as mqtt except ImportError: print(“MQTT client not find. Please install as follow:”) print(“pip install paho-mqtt”)

#Demo_02 ProductKey = “*********”#使用你自己的 ClientId = “2234” # 自定义clientId DeviceName = “Demo_02” DeviceSecret =”**********************************8″#使用你自己的

us = math.modf(time.time())[0] ms = int(round(us * 1000)) timestamp = str(ms)

def calculation_sign(signmethod): data = “”.join((“clientId”, ClientId, “deviceName”, DeviceName, “productKey”, ProductKey, “timestamp”, timestamp))

strBroker = ProductKey + “.iot-as-mqtt.cn-shanghai.aliyuncs.com” port = 1883

client_id = “”.join((ClientId, “|securemode=3”, “,signmethod=”, “hmacsha1”, “,timestamp=”, timestamp, “|”)) username = “”.join((DeviceName, “&”, ProductKey)) password = calculation_sign(“hmacsha1”)

print(“=”*60) print(strBroker) print(“client_id:”, client_id) print(“username:”, username) print(“password:”, password) print(“=”*60)

def on_connect(client, userdata, flags, rc): print(“OnConnetc, rc: ” + str(rc))

def on_publish(client, msg, rc): if rc == 0: print(“publish success, msg = ” + msg)

def on_subscribe(mqttc, obj, mid, granted_qos): print(“Subscribed: ” + str(mid) + ” ” + str(granted_qos))

def on_log(mqttc, obj, level, string): print(“Log:” + string)

def on_message(mqttc, obj, msg): curtime = datetime.datetime.now() strcurtime = curtime.strftime(“%Y-%m-%d %H:%M:%S”) print(strcurtime + “: ” + msg.topic + ” ” + str(msg.qos) + ” ” + str(msg.payload)) on_exec(str(msg.payload))

def on_exec(strcmd): print(“Exec:”, strcmd) strExec = strcmd

if name == ‘main’: mqttc = mqtt.Client(client_id) mqttc.username_pw_set(username, password) mqttc.on_message = on_message mqttc.on_connect = on_connect mqttc.on_publish = on_publish mqttc.on_subscribe = on_subscribe mqttc.on_log = on_log mqttc.connect(strBroker, port, 120) # mqttc.loop_start() time.sleep(1) temperature =27.55 mqttc.subscribe(“/sys/************/Demo_02/thing/service/property/set”, qos=1) # 换成自己的 #send_mseg = ‘{“pm_25″: %s,”area”:”%s”,”time”:”%s”}’ % (0, 0, datetime.datetime.now()) #send_mseg = ‘{“id”: “1234”, “version”: “1.0”,”params”: {“IndoorTemperature”: %s},”method”: “thing.event.property.post”}’%(temperature) send_mseg = ‘{“params”: {“IndoorTemperature”: %s},”method”: “thing.event.property.post”}’ % (temperature)

五、总结 工作之余了解了一下物联网的发展,看到有意思的东西打算学一下,刚好看到了microPython,震惊之余,决心做点小东西玩玩。 这套框架全部使用python实现,比我了解到的*大多数物联网方案要简单太多,虽然有些开发首先,但是用来实现一些简单设计应该是不成问题的,只要你会python,这套系统可以很快构建。当然python也是非常好学的,长期使用C语言的人根本不需要什么学习就可以上手。记住,你不是一个人在战斗。

Python前景介绍

Python前景介绍

2019年刚到来,作为一个学Python,使用Python的学生来说,这无疑是一个令人振奋的消息——Python编程语言获得了“年度编程语言”的称号! Python之所以获得这一称号,是因为与所有其他语言相比,它在2018年获得了*多的排名。Python语言获得了3.62%的优势,其次是VisualBasic.NET和Java。Python现在肯定已经成为大型编程语言的一部分。近20年来,C、C+和Java一直排在前3名,遥遥*于其他方面。Python现在加入了这3种语言。它是当今大学教学*频繁的*语言,在统计领域排名*,在人工智能编程中排名*,在脚本编写方面排名*,在编写系统测试方面排名*。除此之外,Python在网络编程和科学计算方面也处于*地位。 曾经,Python被称为网红语言。大数据时代的到来,Python进入了人们的视线;人工智能的兴起,Python再次受人关注。语法简单,代码优美,Python开始被广泛的学习。Python凭借着社区强大的第三方库,已经被广泛的应用到各个领域中去,Python是脚本语言,Python是人工智能首选语言,Python是全栈式开发语言。总之,Python无处不在。

浏览器与服务器通信的过程

首先当用户在浏览器的地址栏中敲入了网站的网址 ( 比如: alibaba.com ) ,这时浏览器会首先通过访问的域名来定位到IP (DNS) 从而找到去哪里获取资源, 这时, 浏览器会依次进行如下查找:

1. 浏览器缓存 :

浏览器首先会在自己的缓存中查找有没有对应的域名 – IP匹配, 如果好运的话, 这里就可以直接尝试去访问资源了, 如果运气平平则往下走吧.

2. 系统缓存 :

浏览器缓存中没有命中, 浏览器会告诉操作系统:”嘿, 我在我自己口袋里没找到, 可能丢了, 我得去你那看看”, 然后, 一个系统进程(?)调取系统中的DNS缓存进行查询, 重复上一条的运气判断…

3. 路由器缓存 :

走到这, 运气还真不太好啊, 操作系统也没辙了, 那怎么办呢, 向路由去要要看吧… 重复运气判断…

4. ISP DNS缓存 :

好吧, 真不知道说运气好还是运气不好了, 不废话, 去ISP (网络提供商) 的DNS缓存服务器中寻找了, 一般情况下, 在ISP端的缓存中都能找到相应的缓存记录了, 不该这么背了, 或者… 您的ISP有够菜…

5. 递归搜索…

*无奈的情况发生了, 在前面都没有办法命中的DNS缓存的情况下, ISP的DNS服务器开始从root域名服务器开始进行递归, 顺序是从.com顶级域名服务器到alibaba的域名服务器, 再没找到…好吧, 您认为您要去的网站真的公开存在么…?

两个KEY POINT:

首先我们想想,我们要和接线员通话是不是要约定一个大家都能听得懂的语言,否则我说中文他说英语,这样就谁也听不懂谁的话,也不会完成通话,那么这个约定的语言是什么呢?那就是HTTP协议。

超文本传输协议(HTTP,HyperText Transfer Protocol) 是互联网上应用*为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP*初的目的是为了提供一种发布和接收HTML页面的方法。

我们可以把它理解成一种浏览器和服务器都遵循的一种语法规范,所有的信息都是通过这种语法规范传输的,这样浏览器和服务器都可以正确的理解。

浏览器和服务器一般并不是直接连接上的,而是需要通过中间的网络设备,就像我们的声音并不是直接传到接线员的耳朵里,而是要通过电话线通过电波传送一样,浏览器和服务器所发送的遵循HTTP协议的信息也要通过网络设备的传递才能被对方所接收。而这就需要一种在网络设备(网线)上传输数据的一种通用的语法规范(协议)。这样的协议使用*多的有2种:TCP协议和UDP协议

下面让我们来看看我们浏览网页的时候发生了什么吧。

1.首先我们在地址栏上输入我们想要打开的网址,然后我们通常会按下回车。这样一个请求就由浏览器以一种满足http协议的请求报文的形式发往服务器,请求报文中包含了要请求的页面地址,请求的文件类型等一系列信息。

2.在请求报文传递至客户端得网络设备的时候,网络设备把请求报文包装在一个满足TCP协议的数据中,通过网线传向服务器的网络设备。

3.服务器的网络设备接收到数据后,使用特殊的算法将数据解译,重新恢复成浏览器发出满足http协议的请求报文的形式,然后传向服务器软件。

4.服务软件得到请求报文后,根据请求报文所请求的页面地址在服务器的数据库中找到相应的页面,然后生成满足http协议的响应报文发向浏览器。响应报文中包括了响应报文头和被请求页面的代码(响应报文体)。

5.同样的,响应报文通过服务器的网络设备,被包装在一个满足TCP协议的数据,通过网线传向客户端的网络设备。

6.客户端的网络设备将响应报文解析,然后传给浏览器软件,浏览器在将响应报文解析,这样我们就在浏览器上看到了想要看到的网页。

B/S(Browser/Server)结构

就是浏览器/服务器结构,它是随着Internet技术的兴起,对C/S结构的一种变化或者改进的结构。在这种结构下,用户工作界面是通过WWW浏览器来实现,*少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。本文将主要讲解浏览器和服务器通信的过程。

浏览器和服务器之间的通讯并不是看上去那么简单,里面还是有着许多的门道的。想要简单理解浏览器和服务器之间的通讯,我们可以打一个简单的比方:

设想我们自己就是浏览器,服务器就是10086语音服务台,我们现在想要和10086服务台取得联系(比如说想骚扰接线员MM),我们该怎么办呢?

当然,大多数人都应该想到,那就是要有部电话。是这样的,这就引出了我们的*个概念:套接字(Socket)

套接字在百度百科上的解释是:

多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了称为套接字(Socket)的接口。

这个解释太学术了,我们可以简单把套接字理解成一个电话,我们可以从中发送信息和获取信息。

好了,电话有了,我们该给10086服务台打电话了。等等,我们是不是忘了一点,给10086打电话是不是要保证10086服务台也要有一部电话来等待我们的来电呢?对的,那么就是说服务器端也要有一个套接字,专门接受浏览器的请求。一般当一个服务器启动服务后就会开启一个监听连接的套接字,专门等待浏览器连接,接受浏览器请求。

接下来我们要开始打电话了。大多数人都应该有给10086服务台打电话的经验吧,接通后并不是马上由接线员MM来接听你的电话的,而是根据语音提示选择你想要的服务。当你选择了语音服务以后,系统才会自动给你安排一个接线员MM来接听你的电话。那么这个过程是不是又生成了一个套接字呢?是的,没错,我们可以把呼叫系统(也就是给你语音提示,让你选择服务的系统)当成专门接受浏览器的请求的那个套接字,当浏览器发送了一个请求后系统自动生成一个专门和你的浏览器通信的套接字,这样我们就可以和接线员MM通话了,浏览器也就可以和服务器通信了。

当然这远远不是B/S结构的全部,我们还需要进一步深化:

首先我们想想,我们要和接线员通话是不是要约定一个大家都能听得懂的语言,否则我说中文他说英语,这样就谁也听不懂谁的话,也不会完成通话,那么这个约定的语言是什么呢?那就是HTTP协议。

还是先来看百度百科上的解释:

超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用*为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP*初的目的是为了提供一种发布和接收HTML页面的方法。

我们就可以把它理解成一种浏览器和服务器都遵循的一种语法规范,所有的信息都是通过这种语法规范传输的,这样浏览器和服务器都可以正确的理解。

浏览器和服务器一般并不是直接连接上的,而是需要通过中间的网络设备,就像我们的声音并不是直接传到接线员的耳朵里,而是要通过电话线通过电波传送一样,浏览器和服务器所发送的遵循HTTP协议的信息也要通过网络设备的传递才能被对方所接收。而这就需要一种在网络设备(网线)上传输数据的一种通用的语法规范(协议)。这样的协议使用*多的有2种:TCP协议和UDP协议

TCP—传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

UDP—用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

不管使用哪种方法,总之这样网络设备间也有了一套传输的协议,这样一来,浏览器和服务器才能真正的实现通信。

下面让我们来看看我们浏览网页的时候发生了什么吧。

1.首先我们在地址栏上输入我们想要打开的网址,然后我们通常会按下回车。这样一个请求就由浏览器以一种满足http协议的请求报文的形式发往服务器,请求报文中包含了要请求的页面地址,请求的文件类型等一系列信息。

2.在请求报文传递至客户端得网络设备的时候,网络设备把请求报文包装在一个满足TCP协议的数据中,通过网线传向服务器的网络设备。

3.服务器的网络设备接收到数据后,使用特殊的算法将数据解译,重新恢复成浏览器发出满足http协议的请求报文的形式,然后传向服务器软件。

4.服务软件得到请求报文后,根据请求报文所请求的页面地址在服务器的数据库中找到相应的页面,然后生成满足http协议的响应报文发向浏览器。响应报文中包括了响应报文头和被请求页面的代码(响应报文体)。

5.同样的,响应报文通过服务器的网络设备,被包装在一个满足TCP协议的数据,通过网线传向客户端的网络设备。

6.客户端的网络设备将响应报文解析,然后传给浏览器软件,浏览器在将响应报文解析,这样我们就在浏览器上看到了想要看到的网页。

以上只是浏览器与服务器之间通信的*简单的形式,实际使用中,一个网页往往包含着html代码,js代码,css样式表,图片等等多种数据,而这些数据并不是一次性由服务器传给浏览器的,而是存在着一定的顺序。首先服务器收到浏览器的请求后会将html代码发给浏览器,浏览器收到响应后会解析响应报文,发现html代码中包含着js代码和css样式表,而浏览器端并没有这些数据,所以浏览器会再次发送请求,向服务器请求js代码或css样式表数据(注意一次只能请求一种类型的数据),服务器收到请求后,会根据浏览器的请求再次找到数据库中的js文件或css样式表,将其发送到浏览器端。当网页中包含图片的时候也是同理。就这样循环往复,经过多次浏览器的请求和服务器的响应,当浏览器发现自己已经有了所有需要的数据后,会停止发送请求,这样一个完整的网页就呈现在我们眼前了。

以上只是浏览器与服务器之间通信的大致过程,要想详细了解其中门道还请各位参考更详细的文章。

如何快速掌握云计算技术 Linux入门知识有哪些

何快速掌握云计算技术?Linux入门知识包括什么?Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的操作系统。在实际应用中,Linux多与云计算挂扣,很多企业在招聘云计算人才时也会考察其对Linux的掌握程度。接下就给大家分享一下Linux入门知识。

%title插图%num

1、*对路径、当前目录、上层目录、主目录分别用什么表示? 如何切换目录用什么命令?

*对路径:如/etc/init.d

当前目录和上层目录:./ ../

主目录:~/

切换目录:cd

2、清屏、出当前命令、执行睡眠、查看当前用户 id用什么命令?

清屏:clear

退出当前命令:ctrl+c 彻底退出

执行睡眠 :ctrl+z 挂起当前进程fg 恢复后台

查看当前用户 id:”id“:查看显示目前登陆账户的 uid 和 gid 及所属分组及用户名

3、Ls命令执行什么功能?可以带哪些参数,有什么区别?

Ls执行的功能:列出指定目录中的目录以及文件

哪些参数以及区别:a 所有文件;l 详细信息,包括大小字节数,可读可写可执行的权限等

4、目录创建用什么命令?创建文件用什么命令?复制文件用什么命令?

创建目录:mkdir

创建文件:典型的如 touch,vi 也可以创建文件,其实只要向一个不存在的文件输出,都会创建文件

复制文件:cp

5、文件权限修改用什么命令?格式是怎么样的?

文件权限修改:chmod

格式如下:

$ chmod u+x file 给 file 的属主增加执行权限

$ chmod 751 file 给 file 的属主分配读、写、执行(7)的权限,给 file 的所在组分配读、执行(5)的权限,给其他用户分配执行(1)的权限

$ chmod u=rwx,g=rx,o=x file 上例的另一种形式

$ chmod =r file 为所有用户分配读权限

$ chmod 444 file 同上例

$ chmod a-wx,a+r file同上例

$ chmod -R u+r directory 递归地给 directory 目录下所有文件和子目录的属主分配读的权限

6、查看文件内容有哪些命令可以使用?

vi 文件名 #编辑方式查看,可修改

cat 文件名 #显示全部文件内容

more 文件名 #分页显示文件内容

less 文件名 #与 more 相似,更好的是可以往前翻页

tail 文件名 #仅查看尾部,还可以指定行数

head 文件名 #仅查看头部,还可以指定行数

7、Linux下命令有哪几种可使用的通配符?

“?”可替代单个字符

“*”可替代任意多个字符

方括号“[charset]”可替代 charset 集中的任何单个字符,如[a-z],[abABC]

8、Linux中进程有哪几种状态?

1)不可中断状态:进程处于睡眠状态,但是此刻进程是不可中断的。不可中断, 指进程不响应异步信号。

2)暂停状态/跟踪状态:向进程发送一个SIGSTOP信号,它就会因响应该信号 而进入TASK_STOPPED状态;当进程正在被跟踪时,它处于TASK_TRACED这个特殊的状态。

“正在被跟踪”指的是进程暂停下来,等待跟踪它的进程对它进行操作。

3)就绪状态:在run_queue队列里的状态

4)运行状态:在run_queue队列里的状态

5)可中断睡眠状态:处于这个状态的进程因为等待某事件的发生而被挂起

6)zombie状态(僵尸):父亲没有通过wait系列的系统调用会顺便将子进程的尸体(task_struct)也释放掉

7)退出状态

当然,除了以上内容,Linux相关的知识点还有很多,在此就不一一列举了。如果你想成为一个优秀的云计算人才,除了要掌握Linux知识外,还要了解数据库知识、Docker容器、Shell脚本运维、Python语言等,如果你想快速掌握这一系列的技术,可以选择专业的学习,快速掌握企业所需的高薪技术!

没有基础怎么学云计算 多云有哪些优势和挑战

没有基础怎么学云计算?多云有哪些优势和挑战?据IDC调研报告显示,在过去五年里,采用云(包括公有云和私有云)的用户呈指数级增长趋势。多云的出现是为了弥补公有云和私有云各自存在的不足,但这并不意味着多云就毫无缺点。接下来就给大家分析一下多云的优势以及存在的挑战。

%title插图%num

多云的优势

1、解决”单一云”的诸多挑战。多云将多个云的优势相结合,使组织能够使用合适的平台来满足合规性和安全性,而不影响其他工作负载的敏捷性,也不会限制对提供新计划或试点项目的新兴服务的获取。

2、更高的安全性。多云平台通过为组织提供根据合规性要求在适当平台中部署工作负载的灵活性,具备更高的安全性。

3、更高的敏捷性和速度。多云满足了不同企业的工作负载需求,根据企业的情况来选择不同的云,挑战将会更少,这对于企业部署业务的速度将大大提升。

4、为企业提供更广泛的云优势。多云可以为每个企业选择*适合其需求的服务,并提供灵活性,而不必受整个业务中的某个框架的约束。

多云面临的挑战

1、成本相对较高。虽然从一开始就通过利用多个云计算提供商来实现成本效率似乎是合理的,但从长远来看,缺乏工具和标准,以及低效率来跟踪云平台的使用和成本,可能代价更加高昂。

2、在数据迁移方面,客户使用多云面临的主要挑战是,云之间的数据迁移、各个平台缺乏统一的安全监督、所有平台之间缺乏一致的管理结构,以及无法快速部署应用程序。

3、缺乏一致的基础架构、缺乏统一的监视工具,以及各种云之间缺乏共享的专用网络,也被指出是企业正在努力解决的问题。

综合来看,多云是企业未来的趋势,但企业在选择多云的时候还需要尽量考虑周全,尽量选择一些知名度较高的企业来合作部署多云。对于想要加入云计算行业的开发人员来说,现在*对是入行的好时机。如果你不知道如何学习,不妨选择专业的学习,让自己理论与实战兼备,毕业后快速入职拿高薪!

云计算为什么要学Docker容器 该怎样快速入门

云计算为什么要学Docker容器?该怎样快速入门?“云计算”作为未来网络甚至未来计算机行业的发展趋势,得到了广泛重视。越来越多的人想通过学习云计算收获高薪,很多人会发现学习云计算的过程中会接触到Docker容器,这究竟是为什么?如何快速高效的学好Docker容器、进而学好云计算呢?下面且看小编的分析。

%title插图%num

Docker是基于Linux 容器技术的开源项目,它使用Luinux的内核功能(如命名空间和控制组)在操作系统上创建容器。Docker容器具有四大优势:

1)使用简单:Docker 的口头禅是:“一次构建,处处运行”。它使得任何人(开发人员,运维,架构师和其他人)都可以更轻松的利用容器的优势来快速构建和测试可移植的应用程序。

2)速度:Docker容器非常轻量级和快速,因为容器只是运行在内核上的沙盒环境,因此它们占用的资源更少。与可能需要更多时间来创建的虚拟机相比,你可以在几秒钟内创建一个Docker容器。

3)Docker Hub:Docker Hub拥有数万个由社区构建的公共镜像,这些镜像都是随时可用的。Docker用户可以从日益丰富的Docker Hub生态中受益,可以把Docker Hub看作是“Docker 镜像的应用商店”。

4)模块化和可扩展性:Docker可以让你轻松地把应用程序按功能拆分为单个独立的容器。使用Docker,将这个容器链接在一起以创建你的应用程序将会变得更简单,同时在将来可以很轻松地扩展和更新单独的组件。

想要快速入门Docker容器技术,你需要了解Docker容器的安装与启动、镜像操作、应用部署、备份与迁移等知识。同时,Docker容器技术多是与云计算相结合,想要学好Docker找到好工作,参加专业的云计算培训班是明智的。

如果你想成为一个优秀的云计算人才,要掌握Linux知识,了解数据库知识、Docker容器、Shell脚本运维、Python语言等,如果你想快速掌握这一系列的技术,专业的学习让你高效、快速掌握企业所需的高薪技术!

DL-常用函数及其作用

DL-常用函数及其作用

1、optimizer.zero_grad(),loss.backward()和optimizer.step()三个函数
在用pytorch训练模型时,通常会在遍历epochs的过程中依次用到optimizer.zero_grad(),loss.backward()和optimizer.step()三个函数,如下所示:

model = MyModel()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9, weight_decay=1e-4)

for epoch in range(1, epochs):
for i, (inputs, labels) in enumerate(train_loader):
output= model(inputs)
loss = criterion(output, labels)

# compute gradient and do SGD step
optimizer.zero_grad()
loss.backward()
optimizer.step()
总得来说,这三个函数的作用是先将梯度归零(optimizer.zero_grad()),然后反向传播计算得到每个参数的梯度值(loss.backward()),*后通过梯度下降执行一步参数更新(optimizer.step())

optimizer.zero_grad():

def zero_grad(self):
r”””Clears the gradients of all optimized :class:`torch.Tensor` s.”””
for group in self.param_groups:
for p in group[‘params’]:
if p.grad is not None:
p.grad.detach_()
p.grad.zero_()
optimizer.zero_grad()函数会遍历模型的所有参数,通过p.grad.detach_()方法截断反向传播的梯度流,再通过p.grad.zero_()函数将每个参数的梯度值设为0,即上一次的梯度记录被清空。

清零原因:训练的过程通常使用mini-batch方法,如果不将梯度清零的话,梯度会与上一个batch的数据相关,因此该函数要写在反向传播和梯度下降之前。
loss.backward():
PyTorch的反向传播(即tensor.backward())是通过autograd包来实现的,autograd包会根据tensor进行过的数学运算来自动计算其对应的梯度。

具体来说,torch.tensor是autograd包的基础类,

如果设置tensor的requires_grads为True,就会开始跟踪这个tensor上面的所有运算,

如果做完运算后使用tensor.backward(),所有的梯度就会自动运算,tensor的梯度将会累加到它的.grad属性里面去。

更具体地说,损失函数loss是由模型的所有权重w经过一系列运算得到的,

若某个w的requires_grads为True,则w的所有上层参数(后面层的权重w)的.grad_fn属性中就保存了对应的运算,

然后在使用loss.backward()后,会一层层的反向传播计算每个w的梯度值,并保存到该w的.grad属性中。

如果没有进行tensor.backward()的话,梯度值将会是None,因此loss.backward()要写在optimizer.step()之前。
optimizer.step():

以SGD为例,torch.optim.SGD().step()源码如下:

def step(self, closure=None):
“””Performs a single optimization step.
Arguments:
closure (callable, optional): A closure that reevaluates the model
and returns the loss.
“””
loss = None
if closure is not None:
loss = closure()

for group in self.param_groups:
weight_decay = group[‘weight_decay’]
momentum = group[‘momentum’]
dampening = group[‘dampening’]
nesterov = group[‘nesterov’]

for p in group[‘params’]:
if p.grad is None:
continue
d_p = p.grad.data
if weight_decay != 0:
d_p.add_(weight_decay, p.data)
if momentum != 0:
param_state = self.state[p]
if ‘momentum_buffer’ not in param_state:
buf = param_state[‘momentum_buffer’] = torch.clone(d_p).detach()
else:
buf = param_state[‘momentum_buffer’]
buf.mul_(momentum).add_(1 – dampening, d_p)
if nesterov:
d_p = d_p.add(momentum, buf)
else:
d_p = buf

p.data.add_(-group[‘lr’], d_p)

return loss
step()函数的作用是执行一次优化步骤,通过梯度下降法来更新参数的值。因为梯度下降是基于梯度的,所以在执行optimizer.step()函数前应先执行loss.backward()函数来计算梯度。

注意:optimizer只负责通过梯度下降进行优化,而不负责产生梯度,梯度是tensor.backward()方法产生的。

参考https://blog.csdn.net/PanYHHH/article/details/107361827
2、assert(断言)

用于判断一个表达式,在表达式条件为 false 的时候触发异常。

断言可以在条件不满足程序运行的情况下直接返回错误,而不必等待程序运行后出现崩溃的情况,例如我们的代码只能在 Linux 系统下运行,可以先判断当前系统是否符合条件。

使用实例

>>> assert True # 条件为 true 正常执行
>>> assert False # 条件为 false 触发异常
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
AssertionError
>>> assert 1==1 # 条件为 true 正常执行
>>> assert 1==2 # 条件为 false 触发异常
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
AssertionError

>>> assert 1==2, ‘1 不等于 2’
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
AssertionError: 1 不等于 2
>>>
3、torch.cat()

函数目的: 在给定维度上对输入的张量序列seq 进行连接操作。

outputs = torch.cat(inputs, dim=0) → Tensor
参数

inputs : 待连接的张量序列,可以是任意相同Tensor类型的python 序列
dim : 选择的扩维, 必须在0到len(inputs[0])之间,沿着此维连接张量序列。
C = torch.cat( (A,B),0 ) #按维数0拼接(竖着拼)

C = torch.cat( (A,B),1 ) #按维数1拼接(横着拼)
示例

>>> import torch
>>> A=torch.ones(2,3) #2×3的张量(矩阵)
>>> A
tensor([[ 1., 1., 1.],
[ 1., 1., 1.]])
>>> B=2*torch.ones(4,3) #4×3的张量(矩阵)
>>> B
tensor([[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])
>>> C=torch.cat((A,B),0) #按维数0(行)拼接
>>> C
tensor([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.],
[ 2., 2., 2.]])
>>> C.size()
torch.Size([6, 3])
>>> D=2*torch.ones(2,4) #2×4的张量(矩阵)
>>> C=torch.cat((A,D),1)#按维数1(列)拼接
>>> C
tensor([[ 1., 1., 1., 2., 2., 2., 2.],
[ 1., 1., 1., 2., 2., 2., 2.]])
>>> C.size()
torch.Size([2, 7])
4、slice()

slice() 函数返回 slice 对象(切片)。

slice 对象用于指定如何对序列进行裁切。您可以指定在哪里开始裁切以及在哪里结束裁切。您还可以指定步进,例如只切每隔一个项目。

语法:

slice(start, end, step)
参数值

start 可选。整数,指定在哪个位置开始裁切。默认为 0。
end 可选。整数,指定在哪个位置结束裁切。
step 可选。整数,指定裁切的步进值。默认为 1。
示例:

a = (“a”, “b”, “c”, “d”, “e”, “f”, “g”, “h”)

x = slice(2)

print(a[x])
运行结果:
(‘a’, ‘b’)
——————————————–

a = (“a”, “b”, “c”, “d”, “e”, “f”, “g”, “h”)

x = slice(3, 5)

print(a[x])
运行结果:
(‘d’, ‘e’)
———————————————-

a = (“a”, “b”, “c”, “d”, “e”, “f”, “g”, “h”)

x = slice(0, 8, 3)

print(a[x])
运行结果:
(‘a’, ‘d’, ‘g’)
5、 *args:表示接受任意长度的参数,然后存放入一个元组中;如def fun(*args) print(args),‘fruit’,’animal’,’human’作为参数传进去,输出(‘fruit’,’animal’,’human’)

6、**kwargs:表示接受任意长的参数,然后存放入一个字典中;如

def fun(**kwargs):
for key, value in kwargs.items():
print(“%s:%s” % (key,value)
输出:
fun(a=1,b=2,c=3)会输出 a=1 b=2 c=3
7、semilogy()绘图

semilogy 将使用 y 轴的对数刻度绘制数据。

d2l.semilogy(range(1, num_epochs + 1), train_ls, ‘epochs’, ‘rmse’,

range(1, num_epochs + 1), valid_ls,

[‘train’, ‘valid’])
8、plot()绘图

a、plot(y)

当y为向量时,是以y的分量为纵坐标,以元素序号为横坐标,用直线依次连接数据点,绘制曲线。若y为实矩阵,则按列绘制每列对应的曲线。

b、plot(x,y)

若y和x为同维向量,则以x为横坐标,y为纵坐标绘制连线图。若x是向量,y是行数或列数与x长度相等的矩阵,则绘制多条不同色彩的连线图,x被作为这些曲线的共同横坐标。若x和y为同型矩阵,则以x,y对应元素分别绘制曲线,曲线条数等于矩阵列数。

c、plot(x1,y1,x2,y2,……)

在此格式中,每对x,y必须符合plot(x,y)中的要求,不同对之间没有影响,命令将对每一对x,y绘制曲线。

以上三种格式中的x,y都可以是表达式。plot是绘制一维曲线的基本函数,但在使用此函数之前,须先定义曲线上每一点的x以及y坐标。

9、pytorch detach() item() cpu() numpy()

item()返回的是tensor中的值,且只能返回单个值(标量),不能返回向量,使用返回loss等。

detach阻断反向传播,返回值仍为tensor

cpu()将变量放在cpu上,仍为tensor:

numpy()将tensor转换为numpy:
注意cuda上面的变量类型只能是tensor,不能是其他

loss.item() # 获得loss的值

——————————–

gpu_info.detach() #返回tensor,仍在gpu上

tensor([[ 0.9621, -1.0931, -0.8481],
[-0.1668, -1.3945, 0.6562],
[ 0.6152, 0.4177, -0.3538]], device=’cuda:0′)
——————————————-
gpu_info.cpu()

tensor([[ 0.9621, -1.0931, -0.8481],
[-0.1668, -1.3945, 0.6562],
[ 0.6152, 0.4177, -0.3538]])
———————————–
gpu_info.cpu().numpy()

array([[ 0.9621306 , -1.0930926 , -0.8481391 ],
[-0.1667992 , -1.3945109 , 0.656157 ],
[ 0.6151904 , 0.41773367, -0.35378388]], dtype=float32)

10、concat方法相当于数据库中的全连接(UNION ALL),可以指定按某个轴进行连接,也可以指定连接的方式join(outer,inner 只有这两种)。

与数据库不同的是concat不会去重,要达到去重的效果可以使用drop_duplicates方法

concat(objs, axis=0, join=’outer’, join_axes=None, ignore_index=False,
keys=None, levels=None, names=None, verify_integrity=False, copy=True):
运行结果:

from pandas import Series,DataFrame,concat

df1 = DataFrame({‘city’: [‘Chicago’, ‘San Francisco’, ‘New York City’], ‘rank’: range(1, 4)})
df2 = DataFrame({‘city’: [‘Chicago’, ‘Boston’, ‘Los Angeles’], ‘rank’: [1, 4, 5]})
print ‘按轴进行内连接\r\n’,concat([df1,df2],join=”inner”,axis=1)
print ‘进行外连接并指定keys(行索引)\r\n’,concat([df1,df2],keys=[‘a’,’b’]) #这里有重复的数据
print ‘去重后\r\n’,concat([df1,df2],ignore_index=True).drop_duplicates()
————————————————————————-
运行结果:
按轴进行内连接
city rank city rank
0 Chicago 1 Chicago 1
1 San Francisco 2 Boston 4
2 New York City 3 Los Angeles 5

进行外连接并指定keys(行索引)
city rank
a 0 Chicago 1
1 San Francisco 2
2 New York City 3
b 0 Chicago 1
1 Boston 4
2 Los Angeles 5

去重后
city rank
0 Chicago 1
1 San Francisco 2
2 New York City 3
4 Boston 4
5 Los Angeles 5

 

内容审核:用python实现内容鉴黄

内容审核:用python实现内容鉴黄

随着网络监管越来越严格,UGC网站都需要针对用户生产的内容,进行审核。

目前大家一般是机器和人工审核的双重过滤。针对大型的UGC网站,如果全部人工审核是不现实的,需要花费大量的人工成本,所以机器审核尤其重要。

废话不多说,给大家介绍下怎么利用python进行鉴黄。

思路
下面给大家说明下图片审核的思路。

视频审核与图片审核是通用的。视频内容实则由音频内容、视频画面内容两个对象组成,视频画面内容的机器审核,业界目前常采用截取画面帧上传识别,*终复用的是图片识别通道对场景、人物、物品进行判断是否违规。

遍历图片每一个像素,进行颜色分区、并记录是否为肤色;

皮肤区域小于 3 个,不是色情;

如果皮肤区域与整个图像的比值小于 15%,那么不是色情图片;

如果*大皮肤区域小于总皮肤面积的 45%,不是色情图片;

皮肤区域数量超过 60个,不是色情图片;

其它情况为色情图片。

关键代码
# 分析区域
def _analyse_regions(self):
# 如果皮肤区域小于 3 个,不是色情
if len(self.skin_regions) < 3:
self.message = “Less than 3 skin regions ({_skin_regions_size})”.format(
_skin_regions_size=len(self.skin_regions))
self.result = False
return self.result

# 为皮肤区域排序
self.skin_regions = sorted(self.skin_regions, key=lambda s: len(s),
reverse=True)

# 计算皮肤总像素数
total_skin = float(sum([len(skin_region) for skin_region in self.skin_regions]))

# 如果皮肤区域与整个图像的比值小于 15%,那么不是色情图片
if total_skin / self.total_pixels * 100 < 15:
self.message = “Total skin percentage lower than 15 ({:.2f})”.format(total_skin / self.total_pixels * 100)
self.result = False
return self.result

# 如果*大皮肤区域小于总皮肤面积的 45%,不是色情图片
if len(self.skin_regions[0]) / total_skin * 100 < 45:
self.message = “The biggest region contains less than 45 ({:.2f})”.format(len(self.skin_regions[0]) / total_skin * 100)
self.result = False
return self.result

# 皮肤区域数量超过 60个,不是色情图片
if len(self.skin_regions) > 60:
self.message = “More than 60 skin regions ({})”.format(len(self.skin_regions))
self.result = False
return self.result

# 其它情况为色情图片
self.message = “色情图片”
self.result = True
return self.result
运行效果

%title插图%num

luffy数据库的创建

luffy数据库的创建

05.luffy数据库的创建
文章目录
05.luffy数据库的创建
一、创建数据库
二、创建用户,授予权限
三、在Django项目中配置
1.在 setting.py (dev.py)中配置
2.通过服务器环境变量来存放/获取密码
一、创建数据库
新建一个luffy数据库

可以使用图形化工具Navicat创建,鼠标点点即可

可以使用命令行创建

# 1.管理员连接数据库
mysql -uroot -p密码

# 2.创建数据库
create database luffy default charset=utf8;

进入到该数据库查看数据库用户

%title插图%num

# 使用luffy数据库
use luffy

# 查看用户
select user,host,password from mysql.user;

# 5.7之上的的版本查看命令 (提示: 5.7之后password字段变成了authentication_string字段)
select user,host,authentication_string from mysql.user;

二、创建用户,授予权限
注意:基于root用户进行的操作

创建luffy用户,授予luffy库所有权限

# 设置权限账号密码
# 授权账号命令:grant 权限(create, update) on 库.表 to ‘账号’@’host’ identified by ‘密码’

# 1.配置任意ip都可以连入数据库的账户 (提示:%表示任意的地址都可以远程链接)
grant all privileges on luffyapi.* to ‘luffyapi’@’%’ identified by ‘Luffy123?’;

# 2.由于数据库版本的问题,可能本地还连接不上,就给本地用户单独配置
grant all privileges on luffyapi.* to ‘luffyapi’@’localhost’ identified by ‘Luffy123?’;

# 3.刷新一下权限。 (提示: 如果不刷新,只会在下次登录时生效。)
flush privileges;

# 只能操作luffy数据库的账户
账号:luffyapi
密码:Luffy123?

三、在Django项目中配置
1.在 setting.py (dev.py)中配置
# 1.安装配置数据库mysql
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: ‘luffy’,
‘USER’: ‘luffy’,
‘PASSWORD’: ‘Luffy123?’,
‘HOST’: ‘localhost’,
‘PORT’: 3306,
‘CHARSET’: ‘utf8’,
}
}

# 2.安装pymysql,或者是mysqlclient
-运气好:一把装好就用mysqlclient
-pip3 install mysqlclient
-或者使用pymysql(django版本超过2.0.7,需要改源码)
-使用pymysql不要忘了在配置文件中加入
import pymysql
pymysql.install_as_MySQLdb()

问题:如果项目上线后代码泄露,数据库密码很容易泄露,安全性不高,所以,一般我们PASSWORD密码不因该存放到pro.py或者dev.py配置文件中。 因此存放到服务器中, 通过环境变量的获取存放。

2.通过服务器环境变量来存放/获取密码

%title插图%num
password = os.getenv(‘mysql_password’,’Luffy12333′) # 或者下面语句
# password = os.environ.get(‘MYSQL_PASSWORD’,’Luffy12333′))

DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: ‘luffy’,
‘USER’: ‘luffy’,
‘PASSWORD’: password,
‘HOST’: ‘localhost’,
‘PORT’: 3306
}
}

import pymysql
pymysql.install_as_MySQLdb()

Windows配置完环境变量需要重启电脑,否则启动项目报错

Linux重新加载配置文件即可

# 方式一:
source /etc/profile
# 方式二:
. /etc/profile

使用pymysql 版本问题出现的报错信息 :

使用pymysql时, Django版本超过 2.0.7 的时候就会出现这种错误

%title插图%num

%title插图%num

# 修改前
query = query.decode(errors=’replace’)

# 修改后
query = query.encode(errors=’replace’)

修改后启动成功

PS: 如果不想使用pymysql,可以直接安装mysqlclient

pip install mysqlclient

# mysqlclient 比较难装, 运气好一次可以装好, 是在不行不要强求