Python学习日记(三十一) 黏包问题
import subprocess res = subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
print('Stdout:',res.stdout.read().decode('gbk'))
print('Stderr:',res.stderr.read().decode('gbk'))
PIPE把输出的东西装到一个'水管'里,如果在windows中的编码格式是gbk,执行结果:
Stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 2019/09/16 13:48 <DIR> .
2019/09/16 13:48 <DIR> ..
2019/09/16 13:47 <DIR> .idea
2019/09/16 13:46 21 Client1.py
2019/09/16 13:42 0 Client2.py
2019/09/16 13:48 207 Sever1.py
2019/09/16 01:41 70 time_test.py
2019/09/14 23:51 <DIR> venv
4 个文件 298 字节
4 个目录 45,863,636,992 可用字节 Stderr:
在这里也可以使用os.popen()但是它会不管正确和错误的结果都放在一起,而用subprocess能够分别拿到正确和错误的信息
基于TCP实现的黏包
Sever:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8092))
sk.listen()
conn,addr = sk.accept()
while True:
cmd = input('<<<')
conn.send(cmd.encode('gbk'))
ret = conn.recv(1024).decode('gbk')
print(ret)
conn.close()
sk.close()
Client:
import socket
import subprocess
sk = socket.socket()
sk.connect(('127.0.0.1',8092))
while True:
cmd = sk.recv(1024).decode('gbk')
ret = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
std_out = 'stdout:' + (ret.stdout.read()).decode('gbk')
std_err = 'stderr:' + (ret.stderr.read()).decode('gbk')
print(std_out)
print(std_err)
sk.send(std_out.encode('gbk'))
sk.send(std_err.encode('gbk'))
sk.close()
执行结果:
Sever:
<<<dir;ls
stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 <<<ipconfig
stderr:找不到文件 <<<
Client:
stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 stderr:找不到文件 stdout:
Windows IP 配置 以太网适配器 Bluetooth 网络连接 2: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 以太网适配器 本地连接: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 无线局域网适配器 无线网络连接: 连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.43.1 隧道适配器 本地连接* 3: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : stderr:
当我们在sever端输入dir;ls命令时,只有stdout的结果跑出来,而当我们输入ipconfig这个命令时,系统将上一次dir;ls未执行完的stderr的结果给跑出来。像这样没有接受完全或者接受多了的就是黏包现象。
TCP会有黏包现象但是它不丢包。
基于UDP实现的黏包
Sever:
import socket
sk = socket.socket(type=socket.SOCK_DGRAM)
sk.bind(('127.0.0.1',8092))
msg,addr = sk.recvfrom(10240) while 1:
cmd = input('<<<')
if cmd == 'q':
break
sk.sendto(cmd.encode('gbk'),addr)
msg,addr = sk.recvfrom(10240)
print(msg.decode('gbk')) sk.close()
Client:
import socket
import subprocess
sk = socket.socket(type=socket.SOCK_DGRAM)
addr = ('127.0.0.1',8092)
sk.sendto('Start'.encode('utf-8'),addr)
while 1:
cmd,addr = sk.recvfrom(10240)
ret = subprocess.Popen(cmd.decode('gbk'),shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE)
std_out = 'Stdout:' + (ret.stdout.read()).decode('gbk')
std_err = 'Stderr:' + (ret.stderr.read()).decode('gbk')
print(std_out)
print(std_err)
sk.sendto(std_out.encode('gbk'),addr)
sk.sendto(std_err.encode('gbk'),addr)
sk.close()
执行结果:
Sever:
<<<dir;ls
Stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 <<<dir
Stderr:找不到文件 <<<ipconfig
Stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 2019/09/16 14:43 <DIR> .
2019/09/16 14:43 <DIR> ..
2019/09/16 14:37 <DIR> .idea
2019/09/16 14:43 553 Client1.py
2019/09/16 13:42 0 Client2.py
2019/09/16 14:43 306 Sever1.py
2019/09/16 01:41 70 time_test.py
2019/09/14 23:51 <DIR> venv
4 个文件 929 字节
4 个目录 45,855,449,088 可用字节 <<<pwd
Stderr:
<<<ip
Stdout:
Windows IP 配置 以太网适配器 Bluetooth 网络连接 2: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 以太网适配器 本地连接: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 无线局域网适配器 无线网络连接: 连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.43.1 隧道适配器 本地连接* 3: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : <<<
Client:
Stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 Stderr:找不到文件 Stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 2019/09/16 14:43 <DIR> .
2019/09/16 14:43 <DIR> ..
2019/09/16 14:37 <DIR> .idea
2019/09/16 14:43 553 Client1.py
2019/09/16 13:42 0 Client2.py
2019/09/16 14:43 306 Sever1.py
2019/09/16 01:41 70 time_test.py
2019/09/14 23:51 <DIR> venv
4 个文件 929 字节
4 个目录 45,855,449,088 可用字节 Stderr:
Stdout:
Windows IP 配置 以太网适配器 Bluetooth 网络连接 2: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 以太网适配器 本地连接: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 无线局域网适配器 无线网络连接: 连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.43.1 隧道适配器 本地连接* 3: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : Stderr:
Stdout:
Stderr:'pwd' 不是内部或外部命令,也不是可运行的程序
或批处理文件。 Stdout:
Stderr:'ip' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
可以看出UDP不会有黏包现象,会产生丢包现象,没发完就不发了,不完整也不可靠。
黏包成因
TCP协议的数据传送
拆包机制
当发送端缓冲区的长度大于网卡的MTU时,TCP会将这次发送的数据拆成几个数据包发送出去。MTU是Maximum Transmission Unit的缩写,意思是网络上传送最大数据包,MTU是字节单位,大部分网络设备的MTU都是1500.如果本机的MTU比网关的MTU大,大的数据包就会被拆开来传送,这样会产生很多数据包碎片,增加丢包率,降低网络速度。
在正常情况下它的拆包可理解为:
面向流的通信特点和Nagle算法
TCP(transport control protocol,传输控制协议),是面向连接的,面向流的,提供高可靠性的服务。收发两端(客户端和服务端)都要有一一成对的socket,因此发送端为了将多个发往接收端的包,更有效地发往对方,使用了优化算法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样接收端就难于分辨出来了,必须提供科学的拆包机制。即面向流的通信是无消息保护边界的。
对于空消息:TCP是基于数据流的,于是收发消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制,防止程序卡住,而UDP协议是基于数据报的,即便是你输入的是空内容(直接回车),也可以被发送,UDP协议会帮你封装上消息然后发出去。
可靠黏包的TCP协议:TCP协议数据不会丢,没有收完包,就会下次接收,会继续上次继续接受。
基于tcp协议特点的黏包现象成因
当我们在socket服务端发送值1、2,然后根据优化算法,它会把1先放到这个缓存当中等一等,然后再把2一起封装起来,然后再发出去,因此我们看到的就是黏包现象
这种现象的表面现象是两个send太近且发送的消息太短
发送端可以使1K1K地发送数据,而接收端的应用程序可以两K两K地提走数据,当然也有可能一次提走3K或6K数据,或者一次只提走几个字节的数据。也就是说,应用程序所看到的数据是一个整体,或者说是一个流(stream),一条消息有多少字节对应程序是不可见的,因此TCP协议是面向流的协议,这也是容易出现黏包问题的原因。而UDP协议是面向消息的协议,每个UDP段都是一条消息,应用程序必须以消息单位提取数据,不能一次提取任意字节的数据,这一点和TCP是很不同的。
解决黏包的方法
解决方案一:
Sever:
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept() while True:
cmd = input('<<<')
if cmd == 'q':
conn.send(b'q')
break
conn.send(cmd.encode('gbk'))
num = conn.recv(1024).decode('utf-8')
conn.send(b'ok')
res = conn.recv(int(num)).decode('gbk')
print(res) conn.close()
sk.close()
Client:
import socket
import subprocess sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while True:
cmd = sk.recv(1024).decode('gbk')
if cmd == 'q':
break
res = subprocess.Popen(cmd,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
std_out = res.stdout.read()
std_err = res.stderr.read()
sk.send(str(len(std_out) + len(std_err)).encode('utf-8'))
sk.recv(1024)
print('Stdout:' + std_out.decode('gbk'))
print('Stderr:' + std_err.decode('gbk'))
sk.send(std_out)
sk.send(std_err) sk.close()
执行结果:
Sever:
<<<dir
驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 2019/09/17 15:33 <DIR> .
2019/09/17 15:33 <DIR> ..
2019/09/17 15:31 <DIR> .idea
2019/09/17 15:33 623 Client1.py
2019/09/16 13:42 0 Client2.py
2019/09/17 15:21 389 Sever1.py
2019/09/16 01:41 70 time_test.py
2019/09/14 23:51 <DIR> venv
4 个文件 1,082 字节
4 个目录 45,031,833,600 可用字节 <<<ls
'ls' 不是内部或外部命令,也不是可运行的程序
或批处理文件。 <<<ipconfig Windows IP 配置 以太网适配器 Bluetooth 网络连接 2: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 以太网适配器 本地连接: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 无线局域网适配器 无线网络连接: 连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.43.1 隧道适配器 本地连接* 3: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : <<<
Client:
Stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 2019/09/17 15:33 <DIR> .
2019/09/17 15:33 <DIR> ..
2019/09/17 15:31 <DIR> .idea
2019/09/17 15:33 623 Client1.py
2019/09/16 13:42 0 Client2.py
2019/09/17 15:21 389 Sever1.py
2019/09/16 01:41 70 time_test.py
2019/09/14 23:51 <DIR> venv
4 个文件 1,082 字节
4 个目录 45,031,833,600 可用字节 Stderr:
Stdout:
Stderr:'ls' 不是内部或外部命令,也不是可运行的程序
或批处理文件。 Stdout:
Windows IP 配置 以太网适配器 Bluetooth 网络连接 2: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 以太网适配器 本地连接: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 无线局域网适配器 无线网络连接: 连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.43.1 隧道适配器 本地连接* 3: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : Stderr:
这种写法的好处就是能确定Sever到底要接受多少数据,不好的地方就是多了一次交互
解决方案二:使用struct模块
用struct模块我们能把一个数据类型转换成固定长度的bytes
这里以数字类型举例,'i'代表int类型:
import struct
print(struct.pack('i',2048),len(struct.pack('i',2048))) #b'\x00\x08\x00\x00' 4
print(struct.pack('i',204800),len(struct.pack('i',204800))) #b'\x00 \x03\x00' 4
print(struct.pack('i',2048000),len(struct.pack('i',2048000))) #b'\x00@\x1f\x00' 4
当后面的数值戳过一定范围的时候程序就会报错
Sever:
import socket
import struct
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen()
conn,addr = sk.accept() while True:
cmd = input('<<<')
if cmd == 'q':
conn.send(b'q')
break
conn.send(cmd.encode('gbk'))
num = conn.recv(4)
num = struct.unpack('i',num)[0]
res = conn.recv(int(num)).decode('gbk')
print(res) conn.close()
sk.close()
Client:
import socket
import subprocess
import struct sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while True:
cmd = sk.recv(1024).decode('gbk')
if cmd == 'q':
break
res = subprocess.Popen(cmd,shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
std_out = res.stdout.read()
std_err = res.stderr.read()
len_num = len(std_out) + len(std_err)
num_by = struct.pack('i',len_num)
print('Stdout:' + std_out.decode('gbk'))
print('Stderr:' + std_err.decode('gbk'))
sk.send(num_by)
sk.send(std_out)
sk.send(std_err) sk.close()
执行结果:
<<<dir
驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 2019/09/17 16:25 <DIR> .
2019/09/17 16:25 <DIR> ..
2019/09/17 16:23 <DIR> .idea
2019/09/17 16:25 659 Client1.py
2019/09/16 13:42 0 Client2.py
2019/09/17 16:22 400 Sever1.py
2019/09/17 16:08 288 time_test.py
2019/09/14 23:51 <DIR> venv
4 个文件 1,347 字节
4 个目录 45,025,951,744 可用字节 <<<configip
'configip' 不是内部或外部命令,也不是可运行的程序
或批处理文件。 <<<ipconfig Windows IP 配置 以太网适配器 Bluetooth 网络连接 2: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 以太网适配器 本地连接: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 无线局域网适配器 无线网络连接: 连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.43.1 隧道适配器 本地连接* 3: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : <<<
Sever执行结果
Stdout: 驱动器 C 中的卷是 系统
卷的序列号是 85C0-669A C:\Users\Administrator\PycharmProjects\Internet_program 的目录 2019/09/17 16:25 <DIR> .
2019/09/17 16:25 <DIR> ..
2019/09/17 16:23 <DIR> .idea
2019/09/17 16:25 659 Client1.py
2019/09/16 13:42 0 Client2.py
2019/09/17 16:22 400 Sever1.py
2019/09/17 16:08 288 time_test.py
2019/09/14 23:51 <DIR> venv
4 个文件 1,347 字节
4 个目录 45,025,951,744 可用字节 Stderr:
Stdout:
Stderr:'configip' 不是内部或外部命令,也不是可运行的程序
或批处理文件。 Stdout:
Windows IP 配置 以太网适配器 Bluetooth 网络连接 2: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 以太网适配器 本地连接: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : 无线局域网适配器 无线网络连接: 连接特定的 DNS 后缀 . . . . . . . :
本地链接 IPv6 地址. . . . . . . . : fe80::8c6:36a9:6fa6:8018%14
IPv4 地址 . . . . . . . . . . . . : 192.168.43.216
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 192.168.43.1 隧道适配器 本地连接* 3: 媒体状态 . . . . . . . . . . . . : 媒体已断开
连接特定的 DNS 后缀 . . . . . . . : Stderr:
Client执行结果
实现一个大文件的传输和下载
当我们在网络上传输所有数据时,这些数据都叫数据包,数据包里的所有数据都叫报文,报文里不止有你的数据还有IP地址、MAC地址、端口号等,所有的报文都有报头,这是由协议规定的。所有在网络上传播数据包的协议里都有一个报头。什么时候需要自己定制报文?比如说复杂的应用上就会应用到、传输文件的时候(文件名、文件大小、文件类型、存储路径等)...
其实在网络传输的过程当中处处有协议,协议就是一堆报头和报文(都由字节组成)。
Sever:
import socket
import struct
import json
buffer = 1024
sk = socket.socket()
sk.bind(('127.0.0.1',8080))
sk.listen() conn,addr = sk.accept() head_len = conn.recv(4)
struct.unpack('i',head_len)[0]
json_head = conn.recv(head_len).decode('utf-8')
head = json.loads(json_head)
file_size = head['fileSize'] with open(r'dir\%s'%head['fileName'],'wb') as f:
while file_size:
if file_size >= buffer:
content = conn.recv(buffer)
f.write(content)
file_size -= buffer
else:
content = conn.recv(buffer)
f.write(content)
break
conn.close()
sk.close()
Client:
import socket
import struct
import os
import json sk = socket.socket()
sk.connect(('127.0.0.1',8080))
buffer = 1024
head = {'filePath' : r'C:\Users\Administrator\Desktop\专题\海報資料夾\专题海报',
'fileName' : r'专题海报',
'fileSize' : None}
file_path = os.path.join(head['filePath'],head['fileName'])
file_size = os.path.getsize(file_path) head['fileSize'] = file_size
json_head = json.dumps(head) #字典转成字典
bytes_head = json_head.encode('utf-8') #字符串转bytes head_len = len(bytes_head) #报头的长度
pack_len = struct.pack('i',head_len) sk.send(pack_len) #先发报头的长度
sk.send(bytes_head) #再发bytes类型的报头
with open(r'dir\%s'%file_path,'rb') as f:
while file_size:
if file_size >= buffer:
content = f.read(buffer) # 每次文件读出的内容
sk.send(content)
file_size -= buffer
else:
content = f.read(file_size)
sk.send(content)
break
sk.close()
Python学习日记(三十一) 黏包问题的更多相关文章
- Python学习(三十一)—— Django之路由系统
转载自:http://www.cnblogs.com/liwenzhou/p/8271147.html Django的路由系统 Django 1.11版本 URLConf官方文档 URL配置(URLc ...
- Java学习笔记三十一:Java 包(package)
Java 包(package) 一:包的作用: 如果我们在使用eclipse等工具创建Java工程的时候,经常会创建包,那么,这个包是什么呢. 为了更好地组织类,Java 提供了包机制,用于区别类名的 ...
- Python学习日记(三十六) Mysql数据库篇 四
MySQL作业分析 五张表的增删改查: 完成所有表的关系创建 创建教师表(tid为这张表教师ID,tname为这张表教师的姓名) create table teacherTable( tid int ...
- Python学习札记(三十一) 面向对象编程 Object Oriented Program 2
参考:类和实例 注意理解第七点. NOTE: 1.类是抽象的模板,比如Student类,实例是根据类创建出来的一个个具体的"对象",每个对象都拥有相同的方法,但各自的数据可能不同. ...
- Python学习日记(四十一) Mysql数据库篇 九
前言 索引的主要作用是起到约束和加速查找,ORM框架(sqlalchemy)是用类和对象对数据库进行操作 索引的种类 按种类去分 1.普通索引:能够加速查找 2.主键索引:能够加速查找.不能为空.不能 ...
- Python学习日记(三十八) Mysql数据库篇 六
Mysql视图 假设执行100条SQL语句时,里面都存在一条相同的语句,那我们可以把这条语句单独拿出来变成一个'临时表',也就是视图可以用来查询. 创建视图: CREATE VIEW passtvie ...
- Python学习日记(三十四) Mysql数据库篇 二
外键(Foreign Key) 如果今天有一张表上面有很多职务的信息 我们可以通过使用外键的方式去将两张表产生关联 这样的好处能够节省空间,比方说你今天的职务名称很长,在一张表中就要重复的去写这个职务 ...
- Python学习日记(三十三) Mysql数据库篇 一
背景 Mysql是一个关系型数据库,由瑞典Mysql AB开发,目前属于Oracle旗下的产品.Mysql是目前最流行的关系型数据库管理系统之一,在WEB方面,Mysql是最好的RDBMS(Relat ...
- Python学习日记(二十一) 异常处理
程序中异常的类型 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exception 常规错误的基 ...
随机推荐
- vmware新加磁盘fdisk看不到的处理
虚拟机硬盘空间不够了,做了lvm准备加块硬盘扩容,在vcenter控制台加了磁盘,结果操作系统里面fdisk -l看不到新加的硬盘,又不想重启怎么办,一条命令就可以搞定. # 注意中间有空格echo ...
- 图片验证码识别:ModuleNotFoundError: No module named 'ShowapiRequest'
请求示例 # python3.6.5 # 需要引入requests包 :运行终端->进入python/Scripts ->输入:pip install requests from Show ...
- (十)redis源码解读
一.redis工作机制 redis是 单线程,所有命令(set,get等)都会加入到队列中,然后一个个执行. 二.为什么redis速度快? 1.基于内存 2.redis协议resp 简单.可读.效率高 ...
- jsp标签${fn:contains()}遇到问题记录
在jsp页面要实现这样一个功能,列表的某一列字段要显示的数据,是从后台的一个列表中获取的,数据库里面该列存储的方式是 类似 1,2,3 这样的 主键id数据.显示的时候要根据id显示名称,如果是多个 ...
- Xamarin.Android UnauthorizedAccessException: Access to the path is denied
进行文件读写,勾选了权限 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" / ...
- Java中常量以及常量池
1.举例说明 变量 常量 字面量 int a=10; float b=1.234f; String c="abc"; final long d=10L; a,b,c为变量,d为常量 ...
- Java操作fastDFS
一.加入Maven依赖 <dependency> <groupId>org.csource</groupId> <artifactId>fastdfs- ...
- Python入门学习(1)
静态语言: C/C++.Java 编译器一次性生成目标代码,优化更方便 程序运行速度快 动态语言: Python.JavaScript.PHP 执行程序时需要源代码,维护更灵活 源代码在维护灵活.跨多 ...
- PHP设计模式 - 中介者模式
中介者模式用于开发一个对象,这个对象能够在类似对象相互之间不直接相互的情况下传送或者调解对这些对象的集合的修改. 一般处理具有类似属性,需要保持同步的非耦合对象时,最佳的做法就是中介者模式.PHP中不 ...
- 工厂方法(FactoryMethod)模式
之前说了简单工厂设计模式如果增加一个新的运算的时候需要:增加一个具体的实现类,工厂类中增加一个case分支.也就是说我们不但对扩展开发了,也对修改开放了,违背了开闭原则.当然如果工厂类采用反射的话不存 ...