python 全栈开发,Day36(作业讲解(大文件下载以及进度条展示),socket的更多方法介绍,验证客户端链接的合法性hmac,socketserver)...

 先来回顾一下昨天的内容

黏包现象
粘包现象的成因 :
  tcp协议的特点 面向流的 为了保证可靠传输 所以有很多优化的机制
  无边界 所有在连接建立的基础上传递的数据之间没有界限
  收发消息很有可能不完全相等
  缓存机制,导致没发过去的消息会在发送端缓存
    没接收完的消息会在接收端缓存
解决:
  给应用层定制协议
解决方案一:只发送一条信息
  先发送一个定长表示待发送数据长度的bytes 先接收一个固定长度
  再发送要发送的数据 再按照长度接收数据

解决方案二 :发送的多条信息
  先发送一个定长表示待发送字典长度的bytes 先接收一个固定长度
  再发送要发送字典(字典中存储的是文件信息) 再按照长度接收字典
  再发送文件 再根据字典中的信息接收相应的内容

 

那么这2种方案,如何选择呢?
如果发送数据之前,发送的定制协议超过1个变量时,就应该使用字典
否则,就需要发送多次,比如:文件名的长度,文件名,文件大小的长度,文件的内容...

发送的次数越多,在网络上,就比较浪费时间。
如果将上面的5个变量,放到一个字典里面,只需要发送一次,就可以了。

如果只有1个变量,就使用第一种方案

 

一、作业讲解(大文件下载以及进度条展示)                              

大文件传输:

server.py

import os
import json
import socket
import struct
filepath = r'E:\BaiduYunDownload\[电影天堂www.dy2018.com]移动迷宫3:死亡解药BD国英双语中英双字.mp4'sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()conn,addr = sk.accept()
filename = os.path.basename(filepath)
filesize = os.path.getsize(filepath)
dic = {'filename':filename,'filesize':filesize}
str_dic = json.dumps(dic).encode('utf-8')
len_dic = len(str_dic)
length = struct.pack('i',len_dic)
conn.send(length)   # dic的长度
conn.send(str_dic)  # dic
with open(filepath,'rb') as f:  # 文件while filesize:content = f.read(4096)conn.send(content)filesize -= len(content)'''这里不能减等4096,因为文件,最后可能只有3字节。要根据读取的长度len(content),来计算才是合理的。'''
conn.close()
sk.close()

client.py

import json
import struct
import socketsk = socket.socket()
sk.connect(('127.0.0.1',9000))dic_len = sk.recv(4)
dic_len = struct.unpack('i',dic_len)[0]
dic = sk.recv(dic_len)
str_dic = dic.decode('utf-8')
dic = json.loads(str_dic)
with open(dic['filename'],'wb') as f:  # 使用wb更严谨一些,虽然可以使用abwhile dic['filesize']:content = sk.recv(4096)  #这边的4096,可以不用和server对应,改成1024,也可以dic['filesize'] -= len(content)f.write(content)
sk.close()

先执行server.py,再执行client.py

等待30多秒,当前目录就会出现一个视频文件,打开确认,是否可以播放。

 

客户体验太差了,用户不知道啥时候能接收完,程序到底有没有卡住?下载花了多长时间?都不知道

下面来一个进阶版的,增加进度条和下载时间

主要是修改client.py,代码如下:

import json
import struct
import socket
import sys
import timedef processBar(num, total):  # 进度条rate = num / totalrate_num = int(rate * 100)if rate_num == 100:r = '\r%s>%d%%\n' % ('=' * rate_num, rate_num,)else:r = '\r%s>%d%%' % ('=' * rate_num, rate_num,)sys.stdout.write(r)sys.stdout.flushstart_time = time.time()  # 开始时间sk = socket.socket()
sk.connect(('127.0.0.1',9000))dic_len = sk.recv(4)
dic_len = struct.unpack('i',dic_len)[0]
dic = sk.recv(dic_len)
str_dic = dic.decode('utf-8')
dic = json.loads(str_dic)
with open(dic['filename'],'wb') as f:  # 使用wb更严谨一些,虽然可以使用abcontent_size = 0while True:content = sk.recv(4096)
f.write(content) # 写入文件content_size += len(content) # 接收大小processBar(content_size,dic['filesize']) # 执行进度条函数if content_size == dic['filesize']:break # 当接收的总大小等于文件大小时,终止循环sk.close() # 关闭连接end_time = time.time() # 结束时间 print('本次下载花费了{}秒'.format(end_time - start_time))

执行效果如下:

上面效果展示了100个等号,太长了,那么要缩减到1/3呢?

修改进度条函数

def processBar(num, total):  # 进度条rate = num / totalrate_num = int(rate * 100)if rate_num == 100:r = '\r%s>%d%%\n' % ('=' * int(rate_num / 3), rate_num,) # 控制等号输出数量,除以3,表示显示1/3else:r = '\r%s>%d%%' % ('=' * int(rate_num / 3), rate_num,)sys.stdout.write(r)sys.stdout.flush

再次执行:

 再来一个高级版,显示绿色的飞机

代码如下:

def processBar(num, total):  # 进度条rate = num / totalrate_num = int(rate * 100)pretty = '✈'if rate_num == 100:r = '\r\033[32m{}\033[0m{}%\n'.format(pretty * int(rate_num / 5), rate_num,)else:r = '\r\033[32m{}\033[0m{}%'.format(pretty * int(rate_num / 5), rate_num,)sys.stdout.write(r)sys.stdout.flush

效果如下:

再来一个每秒换色

导入一个随机换色类

import randomclass Prompt(object):  # 提示信息显示colour_dic = {'red': 31,'green': 32,'yellow': 33,'blue': 34,'purple_red': 35,'bluish_blue': 36,'white': 37,}def __init__(self):pass@staticmethoddef display(msg, colour='white'):choice = Prompt.colour_dic.get(colour)# print(choice)if choice:info = "\033[1;{};1m{}\033[1;0m".format(choice, msg)return infoelse:return Falsedef random_color(msg):  # 随机换色colour_list = []for i in Prompt.colour_dic:colour_list.append(i)length = len(colour_list) - 1  # 最大索引值index = random.randint(0, length)  # 随机数ret = Prompt.display(msg, colour_list[index])  # 随机颜色return ret

修改client.py

from Prompt import Promptdef processBar(num, total):  # 进度条rate = num / totalrate_num = int(rate * 100)pretty = Prompt.random_color('✈')  # 随机换色if rate_num == 100:r = '\r{}{}%\n'.format(pretty * int(rate_num / 5), rate_num,)else:r = '\r{}{}%'.format(pretty * int(rate_num / 5), rate_num,)sys.stdout.write(r)sys.stdout.flush

执行效果如下:

 

 增加MD5校验                                                                                                                   

server.py

import os
import json
import socket
import struct
import hashlibsk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()conn, addr = sk.accept()
filename = '[电影天堂www.dy2018.com]移动迷宫3:死亡解药BD国英双语中英双字.mp4'  # 文件名
absolute_path = os.path.join('E:\BaiduYunDownload',filename)  # 文件绝对路径
buffer_size = 1024*1024  # 缓冲大小,这里表示1MBmd5obj = hashlib.md5()
with open(absolute_path, 'rb') as f:while True:content = f.read(buffer_size)  # 每次读取指定字节if content:md5obj.update(content)else:break  # 当内容为空时,终止循环md5 = md5obj.hexdigest()
print(md5)  # 打印md5值dic = {'filename':filename,'filename_md5':str(md5),'buffer_size':buffer_size,'filesize':os.path.getsize(absolute_path)}
str_dic = json.dumps(dic).encode('utf-8')
len_dic = len(str_dic)
length = struct.pack('i', len_dic)
conn.send(length)  # dic的长度
conn.send(str_dic)  # dic
with open(absolute_path, 'rb') as f:  # 文件while dic['filesize']:content = f.read(dic['buffer_size'])conn.send(content)dic['filesize'] -= len(content)'''这里不能减等4096,因为文件,最后可能只有3字节。要根据读取的长度len(content),来计算才是合理的。'''
conn.close()

client.py

import json
import struct
import socket
import sys
import time
import hashlib
import os
from Prompt import Promptdef processBar(num, total):  # 进度条rate = num / totalrate_num = int(rate * 100)pretty = Prompt.random_color('✈')if rate_num == 100:r = '\r{}{}%\n'.format(pretty * int(rate_num / 5), rate_num,)else:r = '\r{}{}%'.format(pretty * int(rate_num / 5), rate_num,)sys.stdout.write(r)sys.stdout.flushstart_time = time.time()  # 开始时间sk = socket.socket()
sk.connect(('127.0.0.1',9000))dic_len = sk.recv(4)
dic_len = struct.unpack('i',dic_len)[0]
dic = sk.recv(dic_len)
str_dic = dic.decode('utf-8')
dic = json.loads(str_dic)md5 = hashlib.md5()
with open(dic['filename'],'wb') as f:  # 使用wb更严谨一些,虽然可以使用abcontent_size = 0while True:content = sk.recv(dic['buffer_size'])  # 接收指定大小f.write(content)  # 写入文件content_size += len(content)  # 接收大小md5.update(content)  # 摘要processBar(content_size,dic['filesize'])  # 执行进度条函数if content_size == dic['filesize']:break  # 当接收的总大小等于文件大小时,终止循环md5 = md5.hexdigest()print(md5)  # 打印md5值if dic['filename_md5'] == str(md5):print(Prompt.display('md5校验正确--下载成功','green'))else:print(Prompt.display('文件验证失败', 'red'))os.remove(dic['filename'])  # 删除文件sk.close()  # 关闭连接end_time = time.time()  # 结束时间
print('本次下载花费了{}秒'.format(end_time - start_time))

执行输出:

 

 

二、socket的更多方法介绍                                                

服务端套接字函数
s.bind()    绑定(主机,端口号)到套接字
s.listen()  开始TCP监听
s.accept()  被动接受TCP客户的连接,(阻塞式)等待连接的到来客户端套接字函数
s.connect()     主动初始化TCP服务器连接
s.connect_ex()  connect()函数的扩展版本,出错时返回出错码,而不是抛出异常公共用途的套接字函数
s.recv()            接收TCP数据
s.send()            发送TCP数据
s.sendall()         发送TCP数据
s.recvfrom()        接收UDP数据
s.sendto()          发送UDP数据
s.getpeername()     连接到当前套接字的远端的地址
s.getsockname()     当前套接字的地址
s.getsockopt()      返回指定套接字的参数
s.setsockopt()      设置指定套接字的参数
s.close()           关闭套接字面向锁的套接字方法
s.setblocking()     设置套接字的阻塞与非阻塞模式
s.settimeout()      设置阻塞套接字操作的超时时间
s.gettimeout()      得到阻塞套接字操作的超时时间面向文件的套接字的函数
s.fileno()          套接字的文件描述符
s.makefile()        创建一个与该套接字相关的文件
更多方法
官方文档对socket模块下的socket.send()和socket.sendall()解释如下:socket.send(string[, flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Returns the number of bytes sent. Applications are responsible for checking that all data has been sent; if only some of the data was transmitted, the application needs to attempt delivery of the remaining data.send()的返回值是发送的字节数量,这个数量值可能小于要发送的string的字节数,也就是说可能无法发送string中所有的数据。如果有错误则会抛出异常。–socket.sendall(string[, flags])
Send data to the socket. The socket must be connected to a remote socket. The optional flags argument has the same meaning as for recv() above. Unlike send(), this method continues to send data from string until either all data has been sent or an error occurs. None is returned on success. On error, an exception is raised, and there is no way to determine how much data, if any, was successfully sent.尝试发送string的所有数据,成功则返回None,失败则抛出异常。故,下面两段代码是等价的:#sock.sendall('Hello world\n')#buffer = 'Hello world\n'
#while buffer:
#    bytes = sock.send(buffer)
#    buffer = buffer[bytes:]
send和sendall方法

 

三、验证客户端链接的合法性                                              

 使用hashlib.md5 加密                                                                                             

为什么要随机字符串,是为了防止客户端的数据被窃取

生成随机的bytes类型数据,它是解不出来的

import os
print(os.urandom(32))

执行输出:

b'PO\xca8\xc8\xf3\xa0\xb5,\xdd\xb8K \xa8D\x9cN"\x82\x03\x86g\x18e\xa7\x97\xa77\xb9\xa5VA'

 

server.py

 

import os
import socket
import hashlibsecret_key = '老衲洗头用飘柔'  # 加密keysk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
while True:try:conn,addr = sk.accept()random_bytes = os.urandom(32)  # 随即产生32个字节的字符串,返回bytesconn.send(random_bytes)  # 发送随机加密keymd5 = hashlib.md5(secret_key.encode('utf-8'))  # 使用secret_key作为加密盐md5.update(random_bytes)  #得到MD5消息摘要ret = md5.hexdigest()  #以16进制返回消息摘要,它是一个32位长度的字符串msg = conn.recv(1024).decode('utf-8')  # 接收的信息解码if msg == ret:print('是合法的客户端')  # 如果接收的摘要和本机计算的摘要一致,就说明是合法的else:conn.close()  # 关闭连接finally:  # 无论如何,都执行下面的代码sk.close()  # 关闭连接break

client.py

import socket
import hashlib
secret_key = '老衲洗头用飘柔'  # 加密key
sk = socket.socket()
sk.connect(('127.0.0.1',9000))urandom = sk.recv(32)  # 接收32字节,也就是os.urandom的返回值
md5_obj = hashlib.md5(secret_key.encode('utf-8'))  # 使用加密盐加密
md5_obj.update(urandom)
sk.send(md5_obj.hexdigest().encode('utf-8'))  # 发送md5摘要
print('-----')
sk.close()  # 关闭连接

先执行server.py,再执行client.py

client输出:-----

server输出:是合法的客户端

 

如果100客户端,来连接呢?秘钥都是通用的。
一般情况下,用在哪些场景呢?
比如公司级别,比如1台机器,向100台服务器获取数据

假如黑客渗透到内网,得知到服务器IP地址。就可以做端口扫描,一台计算机的端口范围是0~65535

扫描6万多次,就能知道了。

 使用hmac加密                                                                                                              

hmac是专门来做客户端合法性的

import hmac
obj = hmac.new(key=b'secret_key',msg=b'100212002155')
print(obj.hexdigest())

执行输出:

27111d37764a2fe5bc79d297e7b54c35

客户端也使用hmac,验证一下,就可以了。

改造server和client

server.py

import os
import socket
import hmacsecret_key = '老衲洗头用飘柔'.encode('utf-8')
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
while True:try:conn,addr = sk.accept()random_bytes = os.urandom(32)conn.send(random_bytes)obj = hmac.new(key=secret_key,msg=random_bytes)ret = obj.hexdigest()msg = conn.recv(1024).decode('utf-8')if msg == ret:print('是合法的客户端')else:conn.close()finally:sk.close()break

client.py

import socket
import hmacsecret_key = '老衲洗头用飘柔'.encode('utf-8')
sk = socket.socket()
sk.connect(('127.0.0.1', 9000))urandom = sk.recv(32)
hmac_obj = hmac.new(key=secret_key, msg=urandom)
sk.send(hmac_obj.hexdigest().encode('utf-8'))
print('-----')
sk.close()

执行效果,同上

 

三、socketserver                                                          

 SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进 程” 专门负责处理当前客户端的所有请求。

它能实现多个客户端,同时连接,它继承了socket

ThreadingTCPServer实现的Soket服务器内部会为每个client创建一个 “线程”,该线程用来和客户端进行交互。

使用ThreadingTCPServer:
创建一个继承自 SocketServer.BaseRequestHandler 的类,必须继承
类中必须定义一个名称为 handle 的方法,必须重写

解读socketserver源码 —— http://www.cnblogs.com/Eva-J/p/5081851.html 

看BaseRequestHandler 的源码,它的hendle方法,是空的

    def handle(self):pass

需要自己去实现

server.py

import socketserver
class MyServer(socketserver.BaseRequestHandler):def handle(self):print(self.request)server = socketserver.ThreadingTCPServer(('127.0.0.1',9000),MyServer)
server.serve_forever()

client.py

import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
sk.close()

先执行server.py,再执行client.py

server输出

E:/python_script/day30/socketserver/server.py
<socket.socket fd=348, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 65459)>

 

每连接一个client.就会触发handle,输出request
监听,等待连接,接收,全由hendle完成了。

server.py

import socketserver
class MyServer(socketserver.BaseRequestHandler):def handle(self):print(self.request)self.request.send(b'hello')  # 跟所有的client打招呼print(self.request.recv(1024))  # 接收客户端的信息server = socketserver.ThreadingTCPServer(('127.0.0.1',9000),MyServer)
server.serve_forever()

client.py

import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
print(sk.recv(1024))
inp = input('>>>').encode('utf-8')
sk.send(inp)
sk.close()

先执行server.py,再执行client.py

client输出:

b'hello'
>>>hi

server输出:

<socket.socket fd=316, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 49176)>
b'hi'

开多个客户端,也可以执行

server能够和多个client通信

 

连续发送                                                                                                                      

client连续发送:

import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
while True:print(sk.recv(1024))#inp = input('>>>').encode('utf-8')sk.send(b'hahaha')
sk.close()

server连续接收:

import socketserver
class MyServer(socketserver.BaseRequestHandler):def handle(self):while True:print(self.request)self.request.send(b'hello')  # 跟所有的client打招呼print(self.request.recv(1024))  # 接收客户端的信息server = socketserver.ThreadingTCPServer(('127.0.0.1',9000),MyServer)
server.serve_forever()

执行效果如下:

如果server端口重复,使用以下代码:

# 设置allow_reuse_address允许服务器重用地址socketserver.TCPServer.allow_reuse_address = True

完整代码如下:

import socketserver
class MyServer(socketserver.BaseRequestHandler):def handle(self):while True:print(self.request)  # 这里不能使用input,否则卡住了self.request.send(b'hello')  # 跟所有的client打招呼print(self.request.recv(1024))  # 接收客户端的信息
if __name__ == '__main__':socketserver.TCPServer.allow_reuse_address = Trueserver = socketserver.ThreadingTCPServer(('127.0.0.1',9000),MyServer)server.serve_forever()

  

 明日默写:

import socketserver
class MyServer(socketserver.BaseRequestHandler):def handle(self):self.request.send(b'hello')msg = self.request.recv(1024)print(msg)if __name__ == '__main__':socketserver.TCPServer.allow_reuse_address = Trueserver = socketserver.ThreadingTCPServer(('127.0.0.1',9000),MyServer)server.serve_forever()

  

转载于:https://www.cnblogs.com/xiao987334176/p/9008331.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/570875.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python中xPath技术和BeautifulSoup的使用

xpath基本知识 XPath语法&#xff1a;使用路径表达式来选取XML或HTML文档中的节点或节点集 路径表达式 nodename:表示选取此节点的所有子节点 / &#xff1a; 表示从根节点选取 // &#xff1a;选择任意位置的某个节点。 . &#xff1a;选取当前节点 .. &#xff1a;选…

Redis集群搭建使用

一:关于redis cluster 1:redis cluster的现状 目前redis支持的cluster特性 1):节点自动发现 2):slave->master 选举,集群容错 3):Hot resharding:在线分片 4):进群管理:cluster xxx 5):基于配置(nodes-port.conf)的集群管理 6):ASK 转向/MOVED 转向机制. 2:redis cluster 架…

为Spring Cloud Config Server配置远程git仓库

简介 虽然在开发过程&#xff0c;在本地创建git仓库操作起来非常方便&#xff0c;但是在实际项目应用中&#xff0c;多个项目组需要通过一个中心服务器来共享配置&#xff0c;所以Spring Cloud配置中心支持远程git仓库&#xff0c;以使分散的项目组更方便的进行协作。 基础环境…

Linux一个命令创建多个目录:seq命令

mkdir $(seq -f %g 1 10) 其他seq用法如下&#xff1a; 它還有三個選項-f, --formatFORMAT use printf style floating-point FORMAT (default: %g)-s, --separatorSTRING use STRING to separate numbers (default: \n)-w, --equal-width equalize width by pad…

div水平垂直居中的六种方法

在平时&#xff0c;我们经常会碰到让一个div框针对某个模块上下左右都居中&#xff08;水平垂直居中&#xff09;&#xff0c;其实针对这种情况&#xff0c;我们有多种方法实现。 方法一: 绝对定位方法&#xff1a;不确定当前div的宽度和高度&#xff0c;采用 transform: trans…

Redis集群监控及Redis桌面客户端

之前在生产环境部署了Redis集群&#xff0c;一直苦于没有工具监控&#xff0c;最近找了下网上推荐redmon和Redislive的比较多&#xff0c;查看了两个项目的github,都几年没有更新&#xff0c;这两个项目应该没有人在维护了&#xff0c;如果哪位有更好的替代方案麻烦告知&#x…

phpcms 添加稿件到栏目 add_content

private $db; private $content_model; public function __construct() {parent::__construct ();$this->content_model pc_base::load_model(content_model);$this->siteid 1; }public function add(){$info[title]标题;$info[description]摘要;$info[content]内容;$i…

Python基础学习数值运算之内建函数

1、abs(num) 返回num的绝对值 2、coerce(num1,num2) 将num1和num2转换为同一类型&#xff0c;然后以一个无级的形式返回 3、divmod(num1,num2) 除法取余运算的结合。返回一个元组(num1/num2,num1%num2)。对浮点型和复数的商进行下舍入&#xff08;复数仅取实数部分的商&am…

GIT安装部署

git git简介 Git不仅是一款开源的分布式版本控制系统&#xff0c;而且有其独特的功能特性&#xff0c;例如大多数的分布式版本控制系统只会记录每次文件的变化&#xff0c;说白了就是只会关心文件的内容变化差异&#xff0c;而Git则是关注于文件数据整体的变化&#xff0c;直接…

mac远程桌面登陆windows

找了苹果官方网站&#xff0c;有付费的&#xff0c;找了appstore 还是没有免费使用的&#xff0c;最后找了微软官方非appstore下载的 Microsoft_Remote_Desktop_Beta 在此下载 http://mac.softpedia.com/get/Utilities/Microsoft-Remote-Desktop-Connection.shtml 实在下载不…

牛客网Wannafly挑战赛15 B车辆安排(模拟)AND C 出队(规律)

传送门 &#xff1a;B题&#xff1a;点我 C题&#xff1a; 点我 题目描述 有n个队伍&#xff0c;每个队伍的人数小于等于5&#xff0c;每辆车最多坐5个人&#xff0c;要求一个队伍的人都在一辆车上&#xff0c;求最少的车数 输入描述: 第一行n第二行n个数&#xff0c;表示每个队…

分布式大数据多维分析(OLAP)引擎Apache Kylin安装配置及使用示例

原文地址&#xff1a;http://lxw1234.com/archives/2016/04/643.htm Apache Kylin是一个开源的分布式分析引擎&#xff0c;提供Hadoop之上的SQL查询接口及多维分析&#xff08;OLAP&#xff09;能力以支持超大规模数据&#xff0c;最初由eBay 开发并贡献至开源社区。它能在亚秒…

Apache Kylin原理学习之Cube的创建与Build

原文地址&#xff1a;http://lxw1234.com/archives/2016/05/655.htm Cube是一种典型的多维数据分析技术&#xff0c;一个Cube可以有多个事实表&#xff0c;多个维表构成。如果您还不了解这些概念&#xff0c;建议您搜索下数据仓库、OLAP、Cube、星型模型、事实表、维度表等等。…

5-12

1,每个递归函数都有两部分&#xff0c;基线条件和递归条件 base case and recursive case 2,调用一个函数的时候&#xff0c;其他的函数调用会暂停并处于未完成的状态 3.调用栈会消耗大量的内存&#xff0c;栈很高的时候意味着计算机要存储大量的函数调用信息&#xff0c;此时的…

kylin与superset集成实现数据可视化

原文地址&#xff1a;http://minirick.duapp.com/kylinyu-supersetji-cheng-shi-xian-shu-ju-ke-shi-hua/?utm_sourcetuicool&utm_mediumreferral apache kylin是一个开源分布式引擎&#xff0c;提供Hadoop之上的SQL查询接口及多维分析&#xff08;OLAP&#xff09;能力以…

Ambari离线部署Hadoop集群踩到的坑

1、远程拷贝HDP组件不全导致安装client时缺少rpm包&#xff0c;手动拷贝解决 2、安装HAWQ&#xff0c;启动时报错 passwordlell ssh hawq hosts &#xff0c;hawq master 和其他主机机拷贝文件输入密码受限&#xff0c;两方面原因&#xff1a; 一 root 用户 ssh 无密登录时 权…

2016012026 管凌波 散列函数的应用及其安全性

2016012026 管凌波 散列函数的应用及其安全性 一、散列函数是什么。 散列函数即为Hash函数&#xff0c;就是把任意长度的输入&#xff08;预映射&#xff09;&#xff0c;通过散列算法&#xff0c;变换成固定长度的输出&#xff0c;该输出就是散列值。这种转换是一种压缩映射&a…

Team Foundation Server (TFS) 2015 安装指导

原文地址&#xff1a;http://www.cnblogs.com/danzhang/p/4718035.html http://www.cnblogs.com/danzhang 张洪君 微软ALM MVP 1. 概述 微软于8月6日发布了大家期待已久的TFS 2015正式版&#xff0c; https://www.visualstudio.com/en-us/news/tfs2015-vs.aspx &#xff0c;…

VM虚拟机链接克隆及linux eth0网卡的快速设置方法

对于后台开发者来说,在学习过程中必然接触众多中间件,在自己的虚拟机进行操作甚至搭建cluster是很常见的事情.我在初学者时摸索出一套快速的克隆虚拟机方法.分享给大家.产品VMware Workstation版本10.0.2 build-1744117这是我的虚拟机命名,我觉得这样的命名比较合适,clone机/服…

一加手机虚拟键失灵解决方案

1、手机摔了一下后下方虚拟键无法使用&#xff0c;尝试多种小白点工具如悬浮菜单、超级小白点、easytouch&#xff0c;安装完后并取得root权限后仍不能弹出悬浮框&#xff0c;找不到原因&#xff0c;原则上来讲的话如果是硬件屏幕摔坏&#xff0c;某哥区域无法响应触摸不应影响…