CRC32、MD5和SHA1是目前用来校验文件信息真实性的主要手段,使用这些校验算法可以发现保存或传输的信息是否受到损坏或篡改,防止文件或信息被恶意篡改。下面将分别介绍这几种校验算法。
crc32 CRC全称为Cyclic Redundancy Check,又叫循环冗余校验。CRC是目前使用中最老的一种校验算法,它是由W. Wesley Peterson在1961年发表的论文中提出,CRC是种根据网络数据封包或电脑档案等数据产生简短固定位数校验码的一种散列函數(HASH,把任意长度的输入通过散列算法,最终变换成固定长度的摘要输出,其结果就是散列值,按照HASH算法,HASH具有单向性,不可逆性),主要用来检测或校验数据传输或者保存后可能出现的错误。生成的数字在传输或者储存之前计算出来并且附加到数据后面,然后接收方进行检验确定数据是否发生变化。一般来说,循环冗余校验的值都是32位的整数。由于本函数易于用二进制的电脑硬件使用、容易进行数学分析并且尤其善于检测传输通道干扰引起的错误,因此获得广泛应用。
尽管CRC在错误检测中非常有用,但CRC并不能可靠地校验数据完整性,这是因为CRC多项式是线性结构,可以非常容易地通过改变数据方式达到CRC碰撞,这里给一个更加通俗的解释,假设一串带有CRC校验的代码在传输中,如果连续出现差错,当出错次数达到一定次数时,那么几乎可以肯定会出现一次碰撞(值不对但CRC结果正确),但随着CRC数据位增加,碰撞几率会显著降低,比如CRC32比CRC16具有更可靠的验证性,CRC64又会比CRC32更可靠,当然这都是按照ITU规范标准条件下。
正因为CRC具有以上特点,对于网络上传输的文件类很少只使用CRC作为校验依据,文件传输相比通信底层传输风险更大,很容易受到人为干预影响。
通信数据的校验,差错控制,检错和纠错能力强,
16位或32位(带符号)
md5,sha1(安全领域) MD5全称为Message-Digest Algorithm 5,又叫摘要算法和哈希算法。是Ronald L. Rivest在1992年间提出的,MD5由MD4、MD3、MD2改进而来,MD5散列长度通常是128位,是目前被大量广泛使用的散列算法之一,主要用于密码加密和文件校验等,虽然MD5比CRC的安全可靠性要高的多,但目前已经找到可行的破解方法。现在网上虽然出现有些破解网站和软件,不过可以肯定实际作用范围相当有限,比如,即使黑客拿到了PASSWORD MD5值,除了暴力破解,即使找到碰撞结果也未必能够影响用户安全问题,因为对于密码还要限定位数、类型等,但是如果是面向数字签名等应用,可能就会被破解掉。
文件加密
数字签名
鉴权协议
128位
验证数据的完整性 -(推荐)比较的列(项)较多的情况,性能会有所提升
sha1 SHA全称为Secure Hash Algorithm,又叫安全散列算法。SHA是由美国国家安全局(NSA)所设计,并由美国国家标准与技术研究院(NIST)发布,SHA家族算法有SHA-1、SHA-224、SHA-256、SHA-384和SHA-512(后四者通常并称SHA2),原理和MD4、MD5相似。SHA可将一个最大2^64位(2305843009213693952字节)信息,转换成一串160位(20字节)的散列值(摘要信息),是目前应用最广的HASH算法。同MD5一样,从理论角度,SHA1也不是绝对可靠,目前也已经找到SHA1的碰撞条件,但“实用”的碰撞算法软件还没出现。于是美国NIST又开始使用SHA2,研究更新的加密算法。
补充:虽然目前这几种校验算法都找到了破解条件,但像目前主流使用的MD5、SHA1还是值得信赖的,因为MD5和SHA1都具有高度的离散性,哪怕是只修改一个字节值都会导致MD5或SHA1值“巨大”变化,从实践角度,不同信息具有相同MD5或SHA1码的可能性非常低,通常认为是不可能的,对于普通的下载文件或操作系统,想通过简单的修改某个字节或某些字节,又要保证文件名、大小和安装可靠性的前提下,想达到MD5、SHA1碰撞效果也几乎是不可能的。
类似于md4,md5
单线程,多线程下载,下载文件的准确性校验拼装
比较对比
内容
算法
校验值
安全性
效率
用途
crc32
多项式除法,16或32位
crc值
比较弱
快
通信数据的校验
md5、sha1
16字节(128位)
hash值或散列值
强
慢
文件加密、数字签名等
python实现方式 md5: 1 2 3 4 5 import hashlib md5 = hashlib.md5() md5.update(bytes('http://www.baidu.com' ,encoding="utf-8" )) result = md5.hexdigest()
SHA1: 1 2 3 4 5 import hashlib sha1 = hashlib.sha1() sha1.update(bytes('how to use sha1 in ' ,encoding="utf-8" )) result = sha1.hexdigest()
CRC32: 1 2 from zlib import crc32result = crc32(b'http://www.baidu.com' )
其中SHA-1与MD5 的最大区别在于其摘要比MD5 摘要长 32 比特。对于强行攻击,产生任何一个报文使之摘要等于给定报文摘要的难度:MD5 是2128 数量级的操作,SHA-1 是2160 数量级的操作。但由于SHA-1 的循环步骤比MD5 多(80:64)且要处理的缓存大(160 比特:128 比特),SHA-1 的运行速度比MD5 慢。
虽然在数据表非常大的时候CRC32会出现大量hash冲突,但是能提供更好的性能,在mysql性能优化能起到很好的作用。查询语句可以这样来写:
1 select id from table where url_crc=%s and url=%s;
https://blog.csdn.net/anypkv/article/details/16823797
https://www.cnblogs.com/zenan/p/9165719.html
基础积累 Python使用struct处理二进制 https://www.cnblogs.com/xywq/p/7594457.html
https://www.cnblogs.com/gala/archive/2011/09/22/2184801.html
有的时候需要用python处理二进制数据,比如,存取文件,socket操作时.这时候,可以使用python的struct模块来完成.可以用 struct来处理c语言中的结构体.
struct模块中最重要的三个函数是pack(), unpack(), calcsize()
1 2 3 4 5 6 7 8 # 按照给定的格式(fmt ),把数据封装成字符串(实际上是类似于c结构体的字节流) pack (fmt , v1, v2, ...) # 按照给定的格式(fmt )解析字节流string,返回解析出来的tuple unpack (fmt , string) # 计算给定的格式(fmt )占用多少字节的内存 calcsize(fmt )
上述fmt中,支持的格式为:
FORMAT
C TYPE
PYTHON TYPE
STANDARD SIZE
NOTES
x
pad byte
no value
c
char
string of length 1
1
b
signed char
integer
1
(3)
B
unsigned char
integer
1
(3)
?
_Bool
bool
1
(1)
h
short
integer
2
(3)
H
unsigned short
integer
2
(3)
i
int
integer
4
(3)
I
unsigned int
integer
4
(3)
l
long
integer
4
(3)
L
unsigned long
integer
4
(3)
q
long long
integer
8
(2), (3)
Q
unsigned long long
integer
8
(2), (3)
f
float
float
4
(4)
d
double
float
8
(4)
s
char[]
string
p
char[]
string
P
void *
integer
(5), (3)
unsigned 无符号
signed 有符号
注1.q和Q只在机器支持64位操作时有意思
注2.每个格式前可以有一个数字,表示个数
注3.s格式表示一定长度的字符串,4s表示长度为4的字符串,但是p表示的是pascal字符串
注4.P用来转换一个指针,其长度和机器字长相关
注5.最后一个可以用来表示指针类型的,占4个字节
为了同c中的结构体交换数据,还要考虑有的c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符来改变对齐方式.定义如下:
C TYPE
范围
unsigned int
0~4294967295
int
-2147483648~2147483647
unsigned long
0~4294967295
long
-2147483648~2147483647
long long最大值
9223372036854775807
long long最小值
-9223372036854775808
unsigned long long的最大值
18446744073709551615
_int64的最大值
9223372036854775807
int64最小值
-9223372036854775808
unsigned_int64的最大值
18446744073709551615
为了同c中的结构体交换数据,还要考虑有的c或c++编译器使用了字节对齐,通常是以4个字节为单位的32位系统,故而struct根据本地机器字节顺序转换.可以用格式中的第一个字符来改变对齐方式.定义如下:
Character
Byte order
Size and alignment
@
native
native 凑够4个字节
=
native
standard 按原字节数
<
little-endian
standard 按原字节数
>
big-endian
standard 按原字节数
!
network (= big-endian)
standard 按原字节数
https://www.cnblogs.com/qionglouyuyu/p/4175480.html
Little和Big指的是内存地址的大小,end指的是数据的末尾。
不同的CPU有不同的字节序类型,这些字节序是指整数在内存中保存的顺序。
最常见的有两种:
1. Little-endian:将低序字节存储在起始地址(低位编址)
2. Big-endian:将高序字节存储在起始地址(高位编址)
Big-endian 的内存顺序和数字的书写顺序是一致的,方便阅读理解。 Little-endian 在变量指针转换的时候地址保持不变,比如 int64* 转到 int32*
各有利弊,统一就好,目前看来是 little-endian成为主流了。
little-endain是小头端编码方式,即内存的低位对应数值低位
Little-endian指内存地址低的地方存数据的末尾(即低字节)
特点:
1.最符合人的思维的字节序
2.地址低位存储值的低位
3.地址高位存储值的高位
4.怎么讲是最符合人的思维的字节序,是因为从人的第一观感来说 :
-低位值小,就应该放在内存地址小的地方,也即内存地址低位
-反之,高位值就应该放在内存地址大的地方,也即内存地址高位
举个例子: 存放值12345678
1 2 3 4 5 6 低地址 ------------------> 高地址 #################################################### 地址 # 100 # 101 # 102 # 103 # #################################################### 值 #0111 ,1000 #0101 ,0110 # 0011 ,0100 # 0001 ,0010 # 7 8 5 6 3 4 1 2
举例的数据要看成16进制,就对了
一个地址8位,一个十六进制4位
所以一个地址存两个十六进制数
big-endain是大头端编码方式,即内存的高位对应数值低位
Big-endian指内存地址高的地方存数据的末尾(即高字节)
特点:
1.最直观的字节序
2.地址低位存储值的高位
3.地址高位存储值的低位
4.为什么说直观,不要考虑对应关系
5.只需要把内存地址从左到右按照由低到高的顺序写出
6.把值按照通常的高位到低位的顺序写出
9.两者对照,一个字节一个字节的填充进去
举个例子: 存放值12345678
1 2 3 4 5 6 低地址 ------------------> 高地址 #################################################### 地址 # 100 # 101 # 102 # 103 # #################################################### 值 # 0001 ,0010 #0011 ,0100 # 0101 ,0110 # 0111 ,1000 # 1 2 3 4 5 6 7 8
例:0x1234要存放进从0x4000开始的内存中
在Little-endian中
内存地址
存放内容
0x4000
0x34
0x4001
0x12
在Big-endian中
内存地址
存放内容
0x4000
0x12
0x4001
0x34
https://www.cnblogs.com/passingcloudss/archive/2011/05/03/2035273.html
例子1:在内存中双字0x01020304(DWORD)的存储方式。
1 2 3 4 内存地址 4000 4001 4002 4003 LE 04 03 02 01 BE 01 02 03 04 注:每个地址存1 个字节,每个字有4 个字节。2 位16 进制数是1 个字节(0xFF =11111111 )。
例子2:如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
1 2 3 4 5 6 big-endian little-endian 0x0000 0x12 0xcd 0x0001 0x23 0xab 0x0002 0xab 0x34 0x0003 0xcd 0x12 x86系列的CPU都是little-endian的字节序。
使用方法是放在fmt的第一个位置,就像‘@5s6sif’
<QqQqQ8s64sQqqq
1 2 3 4 5 6 7 8 9 10 11 12 13 解释: < : little-endain是小头端编码方式,即内存的低位对应数值低位;内存地址低的地方存数据的末尾(即低字节) Q : 第一个字符,长度为unsigned long long;最大值为18446744073709551615 q : 第二个字符,长度为long long;最大值为9223372036854775807 Q : 第三个字符 q : 第四个字符 Q : 第五个字符 8s : 第六个字符;长度为8的字符串; 64s:第七个字符;长度为64的字符串; Q : 第八个字符 q : 第九个字符 q : 第十个字符 q : 第十一个字符
Python之socket(套接字) https://www.cnblogs.com/fanweibin/p/5053328.html
一、概述
传输层实现端到端的通信,因此,每一个传输层连接有两个端点。那么传输层连接的端点是什么呢?不是主机,不是主机的IP地址,不是应用进程,也不是传输层的协议端口。 传输层连接的端点叫做套接字(socket)。
根据RFC793的定义:端口号拼接到IP地址就构成了套接字。所谓套接字,实际上是一个通信端点,每个套接字都有一个套接字序号,包括主机的IP地址与一个16位的主机端口号,即形如(主机IP地址:端口号)。例如,如果IP地址是210.37.145.1,而端口号是23,那么得到套接字就是(210.37.145.1:23)。
总之,套接字Socket=(IP地址:端口号),套接字的表示方法是点分十进制的IP地址后面写上端口号,中间用冒号或逗号隔开。每一个传输层连接唯一地被通信两端的两个端点(即两个套接字)所确定。
套接字可以看成是两个网络应用程序进行通信时,各自通信连接中的一个端点。通信时,其中的一个网络应用程序将要传输的一段信息写入它所在主机的Socket中,该Socket通过网络接口卡的传输介质将这段信息发送给另一台主机的Socket中,使这段信息能传送到其他程序中。因此,两个应用程序之间的数据传输要通过套接字来完成。
在网络应用程序设计时,由于TCP/IP的核心内容被封装在操作系统中,如果应用程序要使用TCP/IP,可以通过系统提供的TCP/IP的编程接口来实现。 在Windows环境下,网络应用程序编程接口称作Windows Socket。为了支持用户开发面向应用的通信程序,大部分系统都提供了一组基于TCP或者UDP的应用程序编程接口(API),该接口通常以一组函数的形式出现,也称为套接字(Socket)。
分类
为了满足不同的通信程序对通信质量和性能的要求,一般的网络系统提供了三种不同类型的套接字,以供用户在设计网络应用程序时根据不同的要求来选择。这三种套接为:流式套接字(SOCK-STREAM)、数据报套接字(SOCK-DGRAM)和原始套接字(SOCK-RAW)。
(1)流式套接字。它提供了一种可靠的、面向连接的双向数据传输服务 ,实现了数据无差错、无重复的发送。流式套接字内设流量控制,被传输的数据看作是无记录边界的字节流。在TCP/IP协议簇中,使用TCP协议来实现字节流的传输,当用户想要发送大批量的数据或者对数据传输有较高的要求时,可以使用流式套接字。
(2)数据报套接字。它提供了一种无连接、不可靠的双向数据传输服务 。数据包以独立的形式被发送,并且保留了记录边界,不提供可靠性保证。数据在传输过程中可能会丢失或重复,并且不能保证在接收端按发送顺序接收数据。在TCP/IP协议簇中,使用UDP协议来实现数据报套接字。在出现差错的可能性较小或允许部分传输出错的应用场合,可以使用数据报套接字进行数据传输,这样通信的效率较高。
(3)原始套接字。该套接字允许对较低层协议(如IP或ICMP)进行直接访问,常用于网络协议分析,检验新的网络协议实现,也可用于测试新配置或安装的网络设备。
套接字属性
套接字的特性由3个属性确定,他们是:域、类型、协议
域指定套接字通信中使用的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络
套接字类型
一个套接字可能有多种不同的通信方式
流套接字,流套接字提供一个有序,可靠,双向节流的链接,流套接字由类型SOCK_STREAM指定,它是在AF_INET域中通过TCP/IP链接实现的,这就是套接字类型(其实就是通信方式)
与流套接字相反,由类型SOCK_DGRAM指定的数据报套接字不建立和维持一个连接,它对可以发送的数据长度有限制,数据报作为一个单独的网络消息被传输,它可能会丢失,复制或乱序
最后一个是套接字协议,通常使用默认就可以了(也就是最后一个参数填0)
调用流程:
bind():指定本地地址。一个套接字用socket()创建后,它其实还没有与任何特定的本地或目的地址相关联。在很多情况下,应用程序并不关心它们使用的本地地址,这时就可以不用调用bind指定本地的地址,而由协议软件为它们选择一个。但是,在某个知名端口(Well-known Port)上操作的服务器进程必须要对系统指定本地端口。所以一旦创建了一个套接字,服务器就必须使用bind()系统调用为套接字建立一个本地地址。
connect():将套接字连接到目的地址。初始创建的套接字并未与任何外地目的地址关联。客户机可以调用connect()为套接字绑定一个永久的目的地址,将它置于已连接状态。对数据流方式的套接字,必须在传输数据前,调用connect()构造一个与目的地的TCP连接,并在不能构造连接时返回一个差错代码。如果是数据报方式,则不是必须在传输数据前调用connect。如果调用了connect(),也并不像数据流方式那样发送请求建连的报文,而是只在本地存储目的地址,以后该socket上发送的所有数据都送往这个地址,程序员就可以免去为每一次发送数据都指定目的地址的麻烦。
listen():设置等待连接状态。对于一个服务器的程序,当申请到套接字,并调用bind()与本地地址绑定后,就应该等待某个客户机的程序来要求连接。listen()就是把一个套接字设置为这种状态的函数。
accept():接受连接请求。服务器进程使用系统调用socket,bind和listen创建一个套接字,将它绑定到知名的端口,并指定连接请求的队列长度。然后,服务器调用accept进入等待状态,直到到达一个连接请求。
send()/recv()和sendto()/recvfrom():发送和接收数据 。在数据流方式中,一个连接建立以后,或者在数据报方式下,调用了connect()进行了套接字与目的地址的绑定后,就可以调用send()和reev()函数进行数据传输。
socket通常也称作”套接字”,用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过”套接字”向网络发出请求或者应答网络请求。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)
socket和file的区别:
file模块是针对某个指定文件进行【打开】【读写】【关闭】
socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】
创建套接字
socket系统调用创建一个套接字并返回一个描述符,该描述符可以用来访问该套接字
创建的套接字是一条通信线路的一个端点,domain参数指定协议族(使用的网络介质),type参数指定这个套接字的通信类型(通信方式),protocot参数指定使用的协议
domain参数可以指定如下协议族
AF_UNIX UNIX域协议(文件系统套接字)
AF_INET ARPA因特网协议
AF_ISSO ISO标准协议
AF_NS Xerox网络协议
AF_IPX Novell IPX协议
AF_APPLETALK Appletalk DDS协议
最常用的套接字域是AF_UNIX和AF_INET,前者用于通过UNIX和Linux文件系统实现本地套接字
socket函数的第二个参数type指定用于新套接字的特性,它的取值包括SOCK_STREAM和SOCK_DGRAM
SOCK_STREAM是一个有序,可靠,面向连接的双向字节流,一般用这个
最后一个protocol参数,将参数设为0表示使用默认协议。
socket_server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import socketip_port = ('127.0.0.1' ,9999 ) sk = socket.socket() sk.bind(ip_port) sk.listen(5 ) while True : print 'server waiting...' conn,addr = sk.accept() client_data = conn.recv(1024 ) print client_data conn.sendall('不要回答,不要回答,不要回答' ) conn.close()
socket_client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import socketip_port = ('127.0.0.1' ,9999 ) sk = socket.socket() sk.connect(ip_port) sk.sendall('请求占领地球' ) server_reply = sk.recv(1024 ) print server_replysk.close()
Web实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import socketdef handle_request (client) : buf = client.recv(1024 ) client.send("HTTP/1.1 200 OK\r\n\r\n" ) client.send("Hello, World" ) def main () : sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost' ,8080 )) sock.listen(5 ) while True : connection, address = sock.accept() handle_request(connection) connection.close() if __name__ == '__main__' : main()
二、解释
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 参数一:地址簇 socket .AF_INET IPv4(默认) socket .AF_INET6 IPv6 socket .AF_UNIX 只能够用于单一的Unix系统进程间通信 参数二:类型 socket .SOCK_STREAM 流式socket , for TCP (默认) socket .SOCK_DGRAM 数据报式socket , for UDP socket .SOCK_RAW 原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。 socket .SOCK_RDM 是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。 socket .SOCK_SEQPACKET 可靠的连续数据包服务 参数三:协议 0 (默认)与特定的地址家族相关的协议,如果是 0 ,则系统就会根据地址格式和套接类别,自动选择一个合适的协议
UDP demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import socket ip_port = ('127.0.0.1' ,9999 ) sk = socket .socket (socket .AF_INET,socket .SOCK_DGRAM,0 ) sk.bind(ip_port) while True: data = sk.recv(1024 ) print data import socket ip_port = ('127.0.0.1' ,9999 ) sk = socket .socket (socket .AF_INET,socket .SOCK_DGRAM,0 ) while True: inp = raw_input('数据:' ).strip() if inp == 'exit' : break sk.sendto(inp,ip_port) sk.close ()
sk.bind(address)
1 s.bind(address ) 将套接字绑定到地址。address 地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。
sk.listen(backlog)
1 2 3 4 开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。 backlog等于5 ,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5 这个值不能无限大,因为要在内核中维护连接队列
sk.setblocking(bool)
1 是否阻塞(默认True ),如果设置False ,那么accept 和recv时一旦无数据,则报错。
sk.accept()
1 2 3 接受连接并返回(conn,address ),其中conn是新的套接字对象,可以用来接收和发送数据。address 是连接客户端的地址。 接收TCP 客户的连接(阻塞式)等待连接的到来
sk.connect(address)
1 连接到address 处的套接字。一般,address 的格式为元组(hostname,port),如果连接出错,返回socket.error错误。
sk.connect_ex(address)
1 同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061
sk.close()
sk.recv(bufsize[,flag])
1 接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag 提供有关消息的其他信息,通常可以忽略。
sk.recvfrom(bufsize[.flag])
1 与recv()类似,但返回值是(data ,address)。其中data 是包含接收数据的字符串,address是发送数据的套接字地址。
sk.send(string[,flag])
1 将string 中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string 的字节大小。
sk.sendall(string[,flag])
1 将string 中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None ,失败则抛出异常。
sk.sendto(string[,flag],address)
1 将数据发送到套接字,address是形式为(ipaddr,port )的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。
sk.settimeout(timeout)
1 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s )
sk.getpeername()
1 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port )。
sk.getsockname()
1 返回套接字自己的地址。通常是一个元组(ipaddr,port )
sk.fileno()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import socketip_port = ('127.0.0.1' ,9999 ) sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0 ) sk.bind(ip_port) while True : data = sk.recv(1024 ) print data import socketip_port = ('127.0.0.1' ,9999 ) sk = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,0 ) while True : inp = raw_input('数据:' ).strip() if inp == 'exit' : break sk.sendto(inp,ip_port) sk.close()
三、实例 智能机器人 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import socketip_port = ('127.0.0.1' ,8888 ) sk = socket.socket() sk.bind(ip_port) sk.listen(5 ) while True : conn,address = sk.accept() conn.sendall('欢迎致电 10086,请输入1xxx,0转人工服务.' ) Flag = True while Flag: data = conn.recv(1024 ) if data == 'exit' : Flag = False elif data == '0' : conn.sendall('通过可能会被录音.balabala一大推' ) else : conn.sendall('请重新输入.' ) conn.close()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import socketip_port = ('127.0.0.1' ,8888 ) sk = socket.socket() sk.connect(ip_port) sk.settimeout(5 ) while True : data = sk.recv(1024 ) print 'receive:' ,data inp = raw_input('please input:' ) sk.sendall(inp) if inp == 'exit' : break sk.close()
具体实现脚本: gateway内部:
Q uint64 q int64 64s —> 64长字符串
Gateway的参数
占位
MessSeq
uint64
SendTime
int64
MessType
uint64
MetaLen
int64
CheckSum
uint64
Version
uint32
Flag
[4]byte
Name
[64]byte
Offset
uint64
WriteDataLen
int64
ReadDataLen
int64
Result
int64
注:
之前Flag [8]byte现在拆分成uint32(Version)和[4]byte(Flag)实际还是8位,上面显示当前gateway是12个参数。从占用空间角度去数就没问题的,所以下面的gw_rw.py是11个参数就不需要调整了
gw_rw.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 import socket import structclass GwFd (object) : def __init__ (self) : self.gwfd = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.fmt = "<QqQqQ8s64sQqqq" def connect (self, ip, port) : self.gwfd.connect((ip,port)) def write (self, volname,offset,buflen,buf) : sendMsg = struct.pack(self.fmt, 0 , 0 , 3002 , 0 , 0 , "" , volname, offset, buflen, 0 , 0 ); self.gwfd.send(sendMsg+buf) recvMsg = self.gwfd.recv(struct.calcsize(self.fmt)) r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11 = struct.unpack(self.fmt, recvMsg) return r10 def read (self,volname,offset,buflen) : sendMsg = struct.pack(self.fmt, 0 , 0 , 3001 , 0 , 0 , "" , volname, offset, 0 , buflen, 0 ); self.gwfd.send(sendMsg) recvMsg = self.gwfd.recv(struct.calcsize(self.fmt)) if len(recvMsg) != struct.calcsize(self.fmt): print("read head error" ) return "" r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11 = struct.unpack(self.fmt, recvMsg) if r11 != 0 : print("read %s res error" % volname) return "" total_data="" while True : recvMsg2 = self.gwfd.recv(buflen) total_data = total_data+recvMsg2 if len(total_data) == r9: break if len(total_data) != buflen: print("data len error" ) return "" return '' .join(total_data) def openVolume (self, volname) : sendMsg = struct.pack(self.fmt, 0 , 0 , 3006 , 0 , 0 , "" , volname, 0 , 0 , 0 , 0 ); self.gwfd.send(sendMsg) recvMsg = self.gwfd.recv(struct.calcsize(self.fmt)) r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11 = struct.unpack(self.fmt, recvMsg) return r11 def size (self, volname) : sendMsg = struct.pack(self.fmt, 0 , 0 , 3004 , 0 , 0 , "" , volname, 0 , 0 , 0 , 0 ); self.gwfd.send(sendMsg) recvMsg = self.gwfd.recv(struct.calcsize(self.fmt)) r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11 = struct.unpack(self.fmt, recvMsg) return r11 def closeVolume (self, volname) : sendMsg = struct.pack(self.fmt, 0 , 0 , 3007 , 0 , 0 , "" , volname, 0 , 0 , 0 , 0 ); self.gwfd.send(sendMsg) recvMsg = self.gwfd.recv(struct.calcsize(self.fmt)) r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11 = struct.unpack(self.fmt, recvMsg) return r11 def removeVolume (self, volname) : sendMsg = struct.pack(self.fmt, 0 , 0 , 3003 , 0 , 0 , "" , volname, 0 , 0 , 0 , 0 ); self.gwfd.send(sendMsg) recvMsg = self.gwfd.recv(struct.calcsize(self.fmt)) r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11 = struct.unpack(self.fmt, recvMsg) return r11 def close (self) : self.gwfd.close()
gw_rw_test8.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 import gw_rwimport sysimport zlibimport hashlibimport optparseimport requestsimport signalimport timeimport copyfrom multiprocessing import Process, JoinableQueuefrom threading import Threadq = JoinableQueue() logQ = JoinableQueue() volUrl = "http://%s:8686/region/pool/vol?volume=%s" class Task : def __init__ (self, begin, end) : self.begin = begin self.end = end class SNBS : def __init__ (self, gw, target, opened=True) : self.gw = gw self.target = target self.opened = opened self.fd = None def clear (self) : self.fd = None self.opened = True return self def connect (self) : if self.fd != None : self.disconnect() self.fd = gw_rw.GwFd() self.fd.connect(self.gw, 8585 ) def disconnect (self) : if self.fd != None : self.fd.close() self.fd = None def open (self) : self.connect() if not self.opened: ret = self.fd.openVolume(self.target) if ret != 0 : err = "target: " + self.target + " gw: " + \ self.gw + " ret: " + str(ret) + " open fail" print(err) raise Exception(err) def close (self) : if not self.opened: self.fd.removeVolume(self.target) self.fd.closeVolume(self.target) if self.fd != None : self.disconnect() def read (self, begin, length) : return self.fd.read(self.target, begin, length) def size (self) : return self.fd.size(self.target) class IMG : def __init__ (self, localvol) : self.file = localvol self.fd = None def clear (self) : self.fd = None def open (self) : if self.fd != None : self.close() self.fd = open(self.file, 'r' ) def close (self) : if self.fd != None : self.fd.close() self.fd = None def read (self, begin, length) : self.fd.seek(begin, 0 ) return self.fd.read(length) class Vol : def __init__ (self, name, type, gw="" ) : self.name = name self.type = type self.gw = gw def main (gw, target, source, sourceType, blocksize, skip, count, hashMethod, process_num) : print("target:" , target, "source:" , source, "type:" , sourceType, "bs:" , blocksize, "skip:" , skip, "count:" , count, "hash:" , hashMethod, "processNum:" , process_num) tar = None src = None try : gwport = queryGW(gw, target) if gwport == "" : targetGW = gw opened = False else : targetGW = gw.split(":" )[0 ] opened = True print("target: %s gw: %s opend: %s" % (target, targetGW, str(opened))) tar = SNBS(targetGW, target, opened) tar.open() size = tar.size() if sourceType == "origin" : gwport = queryGW(gw, source) if gwport == "" : sourceGW = gw opened = False else : sourceGW = gw.split(":" )[0 ] opened = True print("source: %s gw: %s opend: %s" % (source, sourceGW, str(opened))) src = SNBS(sourceGW, source, opened) runTask = localCheck elif sourceType == "local" : src = IMG(source) runTask = localCheck src.open() begin = 0 if skip != 0 : begin = blocksize * skip if begin > size: print("begin offset:" , begin, "target size:" , size) exit(1 ) if count != -1 : end = blocksize * (skip + count) if end > size: print("end offset:" , end, "target size:" , size, "set end:" , size) end = min(end, size) else : end = size for i in range(begin + blocksize, end, blocksize): task = Task(begin, i) q.put(task) begin = i if begin != end: task = Task(begin, end) q.put(task) print("generate task finish" ) t = Thread(target=display, args=(q.qsize(),)) t.setDaemon(True ) t.start() t = Thread(target=displayLog, args=(logQ,)) t.setDaemon(True ) t.start() for _ in range(process_num): p = Process(target=runTask, args=( copy.deepcopy(tar).clear(), copy.deepcopy(src).clear(), hashMethod, q, logQ)) p.daemon = True p.start() q.join() print("Finished" ) except KeyboardInterrupt: while True : try : q.get_nowait() q.task_done() except : print("Terminated" ) break finally : if tar != None : print("closing target: %s gw: %s opend: %s" % (tar.target, tar.gw, str(tar.opened))) tar.close() if src != None : print("closing target: %s gw: %s opend: %s" % (src.target, src.gw, str(src.opened))) src.close() def queryGW (gw, target) : r = requests.get(volUrl % (gw, target), timeout=5 ) res = r.json() if res.get("error" ) != None : raise Exception(" gw: " + gw + "vol: " + target + " not exist" ) return r.json().get("Owner" ) def localCheck (target, source, hashMethod, q, logQ) : try : work = True target.open() source.open() while True : try : task = q.get() if work: str1 = target.read(task.begin, task.end - task.begin) str2 = source.read(task.begin, task.end - task.begin) errTimes = 0 for method in hashMethod: if hashSet[method](str1) != hashSet[method](str2): errTimes += 1 logQ.put("error offset:%d, len:%d, method:%s" % (task.begin, task.end - task.begin, method)) if errTimes != 0 : work = False except KeyboardInterrupt: exit(254 ) finally : q.task_done() finally : target.close() source.close() def originCheck (target, source, gw, hashMethod, q, logQ) : try : fd = gw_rw.GwFd() fd.connect(gw, 8585 ) while True : try : task = q.get() str1 = fd.read(target, task.begin, task.end - task.begin) str2 = fd.read(source, task.begin, task.end - task.begin) if hashMethod(str1) != hashMethod(str2): logQ.put("error offset:%d, len:%d" % (task.begin, task.end - task.begin)) except KeyboardInterrupt: exit(254 ) finally : q.task_done() finally : fd.close() def displayLog (logQ) : while True : log = logQ.get() print(log) def display (total) : while not q.empty(): print("================ task left:%d total:%d ================" % (q.qsize(), total)) time.sleep(1 ) def hashcheck (method) : def check (string) : md5 = method() md5.update(string) return md5.hexdigest() return check hashSet = {"crc32" : zlib.crc32, "md5" : hashcheck(hashlib.md5), "sha1" : hashcheck(hashlib.sha1)} m = hashlib.md5() def aaa (b) : m.update(b) id_md5 = m.hexdigest() print id_md5 if __name__ == "__main__" : p = optparse.OptionParser() p.add_option('--gw' , '-g' ) p.add_option('--target' , '-t' ) p.add_option('--source' , '-s' ) p.add_option('--type' , '-T' , default="origin" ) p.add_option('--blocksize' , '-b' , default=4194304 ) p.add_option('--skip' , '-k' , default=0 ) p.add_option('--count' , '-c' , default=-1 ) p.add_option('--verify' , '-v' , default="crc32" ) p.add_option('--num' , '-n' , default=4 ) options, args = p.parse_args() gw = options.gw target = options.target source = options.source sourceType = options.type blocksize = int(options.blocksize) skip = int(options.skip) count = int(options.count) num = int(options.num) h = options.verify hashMethod = set() if h != "crc32" and h != "md5" and h != "sha1" and h != "all" : raise Exception("unsupport verify hash method: %s" % h) if h == "crc32" or h == "all" : hashMethod.add("crc32" ) if h == "md5" or h == "all" : hashMethod.add("md5" ) if h == "sha1" or h == "all" : hashMethod.add("sha1" ) print("hashMethod:" , hashMethod) main(gw, target, source, sourceType, blocksize, skip, count, hashMethod, num)
使用方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 1. 有时间复现一下磁盘损坏的问题2. 文件在 全闪.6 /root/verify,本地没测。。。。 运行案例:python gw_rw_test2.py -t dev0 -s dev160 -T origin -g 10.37 .2 .20 -n 2 -v crc32 -b 4096 -k 400 -c 40000 3. 各个参数 p. add_option('--gw' ,'-g' ) p. add_option('--target' ,'-t")# target volume p. add_option(' --source',' -s')# source volume p. add_option("--type' ,'-T' , default="origin" ) p. add_option('--blocksize' ,'-b' , default=4194304 ) p. add_option('--skip' ,'-k", default=e)# skip k of blocksize, begin offset=blocksize* skip p. add_option(' --count',' -c', default=-1)# block count p. add_option(' --verify',' -v', default="crc32")# verify hash method, crc32 only now p. add option(' --num',' -n', default=4)# number of process -t是克隆卷/上传卷 -s是原卷/本地卷 -v all ---> md5 + crc32 -v md5 ---> md5 -v crc32 ---> crc32 -v sha1 --->sha1
grpc(gateway和master之间,查询卷之类),因为效率的问题
tcp接口
HTTP接口(应用层)-