一个简单的文件传输验证码识别C/S实现

client通过tcp向server传输一个待识别的验证图片,server端识别后通过tcp回传给client。
server端识别验证码采用pytesseract。
环境:server/python3.5/Ubuntu1604,client/Qt5.3/win7。

1、文件传输

tcp很多人都很熟悉,经常用来传递数据。但如何用于传递文件呢。尝试过的同学可能知道常见的有这么几个问题:

1)文件较大时tcp会分包。

一张图片可能2M甚至更大,当然普通的验证码截图很小400k左右。但考虑到健壮性、通用性,还是应当通过设计来解决这个问题。

2)文件长度不对可能导致损坏

一张图片如果头部少了或者多了一些信息是很有可能导致图片无法打开,更无从说识别。而尾部多了少了相对不那么敏感,但最好不要弄错。试想,如果客户的照片效果很好,由于你在传递过程中多接收或者少接收数据导致打了折扣,加班说不定又要开始了。所以,还是精确为好。
而且如果一个文件是1800字节,一包tcp一般1500字节以内,你rcv一次直接存文件,文件够呛能打开。而如果是300字节的文件,你直接写进去1400字节,肯定有问题。
所以,文件长度是文件传输的一个必须前知的参数。

针对这两个问题,用协议来解决。此处自定义了一个很简单的协议如下:

filename seperator filelen seperator filecontent

也就是将传输的内容分成3段,第一段是文件名,第二段是文件长度,第三段是文件内容。都是以字节流的形式封装传递。

各段用分隔符加以分隔,此处为一个tab。

2、server端代码

刚过完年,笔记本没装pycharm,代码纯用vim写的,所以注释空格很多未符合pep8规则的地方,大家自行忽略。。。vim的插件配置还在摸索。。。

#encoding:utf-8 #!/usr/bin/env python #导入socket模块 import socket import sys import pytesseract from PIL import Image #添加异常处理,添加tcp断链处理与保护判断 def getCode(path): """ get identify code with pytesseract """ img=Image.open(path) vcode=pytesseract.image_to_string(img) print(vcode) return vcode class Proto: def init(self): print("hehe") def decode(self,cont): print("decode in parent") #从第一包数据解析出文件名、长度、文件内容起始处 class HeadAnalyzor(Proto): def init(self): contPos=0 contLen=0 name="" def decode(self,cont): print(cont) nameEnd=cont.find(bytes(' ','utf8')) self.name=cont[0:nameEnd] self.contPos=cont.find(bytes(' ','utf8'),nameEnd+1) print("na %d co %d" %(nameEnd,self.contPos)) self.contLen=(int)(cont[nameEnd:self.contPos]) print("nameEnd %d contPos %d contLen %d" %(nameEnd,self.contLen,self.contLen)) #将文件内容存入文件中 class FileTransferProto(Proto): def decode(self,cont): print(type(cont)) pos=cont.find(bytes(' ','utf8')) name=cont[0:pos] pos=cont.find(bytes(' ','utf8'),pos+1) print(" pos is %d" %(pos)) if pos>0: f=open(name,'wb') print("fName is %s len is %d" %(name,len(cont)-pos)) f.write(cont[pos+1:-1]) f.close() else: print("not found space ") #开启ip和端口 ip_port = ('192.168.65.49',(int)(sys.argv[1])) #生成句柄 web = socket.socket() #绑定端口 web.bind(ip_port) #最多连接数 web.listen(5) #等待信息 print ('nginx waiting...') #阻塞 conn,addr = web.accept() print("accepted") #开启死循环 while True: print("again") #获取客户端请求数据 data = conn.recv(1024000) buf = data #客户端断开链接 if len(data)==0: print("disconnect by peer! rcvLen:%d \n waiting..." %len(data)) #重连 conn,addr=web.accept() continue headAna = HeadAnalyzor() headAna.decode(data) remainLen=headAna.contLen -len(data) + headAna.contPos + 1 rcvLen=len(data) i=0 #直到指定长度的文件内容均接收到后进行存文件操作 while remainLen>0: data=conn.recv(1024) rcvLen+=len(data) remainLen-=len(data) print("times %d remain %d conLen %d rcvLen %d" %(i,remainLen,headAna.contLen,rcvLen)) i+=1 buf+=data proto=FileTransferProto() proto.decode(buf) #向对方发送数据,也即识别出来的验证码 idcode=getCode(headAna.name) print(conn.send(bytes(idcode,'utf8'))) #关闭链接 # conn.close()

运行脚本:

python3 tcpserver.py 8889 3、client端代码

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/8ee8ca25e2f6926f95452a07be7cbcc3.html