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;选…

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

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

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

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

GIT安装部署

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

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

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

5-12

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

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机/服…

Spring MVC+Mybatis 多数据源配置

文章来自&#xff1a;https://www.jianshu.com/p/fddcc1a6b2d8 1. 继承AbstractRoutingDataSource AbstractRoutingDataSource 是spring提供的一个多数据源抽象类。spring会在使用事务的地方来调用此类的determineCurrentLookupKey()方法来获取数据源的key值。我们继承此抽象类…

围观神龙架构首次开箱,现场直播暴力拆机

围观神龙架构首次开箱&#xff0c;现场直播暴力拆机 发布时间&#xff1a;2018-05-16 13:43:01686人关注34人参与阿里云X-Dragon大事记2017年4月&#xff1a;阿里云X-Dragon项目立项&#xff1b;2017年10月&#xff1a;阿里云正式推出基于X-Dragon架构的弹性裸金属服务器&#…

windows-server-2012R2离线中文语言包安装

1、离线包下载地址http://download.csdn.net/detail/github_38358734/9858412 2、安装方法&#xff1a; 解压离线包 Dism /online /Add-Package /PackagePath:C:\test\LangPacks\lp.cab 大概10分钟&#xff0c;完成。 然后重启电脑&#xff0c;到控制面板语言区域选项&…

文字闪烁效果

效果图&#xff1a; HTML Code: <a class"blink" href"#" target"_blank"> 扁平化设计看上去非常简单、直观扁平化设计看上去非常简单、直去非化设计看上去非常简单、直观扁平化设计看上去非常简单、直观扁平常简单</a> JQuery Code…

BZOJ 3295: [Cqoi2011]动态逆序对 cdq分治

https://www.lydsy.com/JudgeOnline/problem.php?id3295 这个妹妹我曾见过的~~~ 之前应该在校内oj写了&#xff0c;似乎还写过题解&#xff1f;发现没写博客就重新水一遍代码水一篇博客好了。 把找逆序对的过程想成一个一个往里塞数字然后找每个数字可以组成的逆序对&#xff…

p1、查询端口号占用,根据端口查看进程信息/p

2017年6月份的时候&#xff0c;我就着手在公司推广git&#xff0c;首先我自己尝试搭建了GitLab来管理代码&#xff0c;并且通过以下博客记录了GitLab的搭建&#xff0c;以及GitLab备份&#xff0c;GitLab升级等事情。 git学习——>在CenterOS系统上安装GitLab并自定义域名访…

point-position2修改版

说明&#xff1a; 在共面直线测试中&#xff0c;由于计算误差等原因&#xff0c;共面条件判断不准&#xff0c;但计算结果依然正确。 // point-position2.cpp : 定义控制台应用程序的入口点。 #include "stdafx.h" #include <stdio.h> #include <iostream&g…

Linux学习总结(十六)系统用户及用户组管理

先来认识两个文件/etc/passwd/etc/shadow我们打印出首尾三行&#xff0c;来了解下&#xff1a;每行由&#xff1a;分割为7段&#xff0c;每段含义为&#xff1a;第一段&#xff1a;用户名&#xff0c;比如root 用户&#xff0c;普通用户test,lv,test1第二段&#xff1a;早期存放…

hadoop综合大作业

Hadoop综合大作业 要求&#xff1a; 1.用Hive对爬虫大作业产生的文本文件&#xff08;或者英文词频统计下载的英文长篇小说&#xff09;词频统计。 词频统计的截图如下&#xff1a; 上次我所使用的文章是一篇中文文章&#xff0c;所以这次我用了一篇英文文档来进行分词&#xf…

MPI对道路车辆情况的Nagel-Schreckenberg 模型进行蒙特卡洛模拟

平台Ubuntu 16.04&#xff0c;Linux下MPI环境的安装见链接&#xff1a;https://blog.csdn.net/lusongno1/article/details/61709460据 Nagel-Schreckenberg 模型&#xff0c;车辆的运动满足以下规则&#xff1a;1. 假设当前速度是 v &#xff0c;和前一辆车的距离为d。2. 如…

Android 中.aar文件生成方法与用法

https://i.cnblogs.com/EditPosts.aspx?opt1 无论是用Eclipse还是用Android Studio做android开发&#xff0c;都会接触到jar包&#xff0c;全称应该是&#xff1a;Java Archive&#xff0c;即java归档文件。在用AS的过程中&#xff0c;你会发现有aar这么个东西&#xff0c;经查…

windows10上安装mysql

环境&#xff1a;windwos 10&#xff08;1511&#xff09; 64bit、mysql 5.7.14 一、下载mysql1. 在浏览器里打开mysql的官网http://www.mysql.com/2. 进入页面顶部的"Downloads"3. 打开页面底部的“Community(GPL) Downloads” 4. 在页面中间的位置找到我们windows上…