mfsocket合法吗_socketserver和socket的补充(验证客户端合法性)

3、验证客户端合法性

场景:如果别人知道了你的服务器的IP,那么他就可以使用扫端口的方式去连接上你的服务器,因为我们都知道,端口的范围是0-65535,

那么别人知道了你的服务器IP后,就可以循环扫这些端口,就可以连接上你的服务,你服务器所进行的一些操作,比如一些数据的传输,

就会被别人所获取,所以这个时候就需要验证客户端的合法性。

代码

服务端:importosimporthmacimportsocketdefauth(conn):

msg= os.urandom(32) #生成一个32位的随机的字节码(urandom生成的字节码就是bytes类型的)

conn.send(msg) #把这个随机的字节码发送到client端

#hmac接收两个参数,第一个参数相当于hashlib的盐,第二个参数是我们随机生成的字节码,两个参数都是bytes类型

result = hmac.new(secret_key,msg) #处理这个随机字节码,socket_key是盐

res = result.hexdigest() #得到结果(字符串)

client_digest = conn.recv(1024) #接收client端处理的结果

if res == client_digest.decode('utf-8'):print('合法的连接') #对比成功可以继续通信

returnTrueelse:print('不合法连接') #不成功

returnFalse

secret_key= b'xiaoming' #hmac的盐

sk =socket.socket()

sk.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

sk.bind(('127.0.0.1',8080))

sk.listen()

conn,addr=sk.accept()ifauth(conn):

msg= conn.recv(1024) #True正常的和client端进行沟通

print(msg.decode('utf-8'))

conn.close()else:

conn.close()#False 直接关闭和这个客户端的连接

sk.close()

客户端:importhmacimportsocketdefauth(sk):

msg= sk.recv(32) #接收服务端传来的随机字节码

result = hmac.new(secret_key,msg) #处理接收到的随机字节码

res = result.hexdigest() #得到结果

sk.send(res.encode('utf-8')) #把结果发回给服务端,让服务端进行验证

secret_key= b'xiaoming' #因为盐是程序员自己设置的,那么程序员写的客户端肯定知道自己的盐是什么

sk =socket.socket()

sk.connect(('127.0.0.1',8080))

auth(sk)

sk.send(b'connect success') #进行其他正常的和server端的沟通

sk.close()

二、socketserver

正常服务端的socket,每一次只能连接一个客户端,只有跟当前客户端断开连接后才能和下一个客户端连接,

而用socketserver可以跟多个客户端同时连接(并发)。

服务端:importsocketserver#tcp协议的server端就不需要导入socket

class Myserver(socketserver.BaseRequestHandler): #继承socketserver.BaseRequestHandler这个类

def handle(self): #必须继承handle方法并重写

conn = self.request #self.request就是客户端的对象

while True: #和客户端进行交互

conn.send(b'helloworld')print(conn.recv(1024).decode('utf-8'))#设置allow_reuse_address允许服务器重用地址

socketserver.TCPServer.allow_reuse_address =True#创建一个对象server,绑定ip和端口,相当于sk = socket.socket() sk.bind(('127.0.0.1',8888))这两步的结合

server = socketserver.ThreadingTCPServer(('127.0.0.1',8888),Myserver)#让server一直运行下去,除非强制停止程序

server.serve_forever()

客户端:importsocket

sk=socket.socket()

sk.connect(('127.0.0.1',8888))whileTrue:

ret= sk.recv(1024)print(ret.decode('utf-8'))

sk.send(b'hiworld')

sk.close()

解释为什么一定要重写handler方法:

Myserver这个类没有__init__方法,那么它就会去继承使用父类BaseRequestHandler的__init__方法

看看BaseRequestHandler源码:classBaseRequestHandler:def __init__(self, request, client_address, server):

self.request= request #获取客户端的连接(对象),设置为自己的属性

self.client_address = client_address #客户端的地址

self.server =server

self.setup()try:

self.handle()#初识化对象的时候执行handler方法

finally:

self.finish()defsetup(self):pass

defhandle(self):pass

deffinish(self):pass总结:

也就是说,子类继承了父类的__init__方法,这个方法里面已经取到了客户端的对象conn,和地址addr,

并且初始化的时候调用了handler方法,但是父类的handler方法并没有实现任何功能,所以子类应该重写handler方法便于与客户端交互。

实例:上传文件

server.pyimportjsonimportstructimportsocketserverimportoperate_handlerclassMyFTP(socketserver.BaseRequestHandler):defhandle(self):

conn=self.request

length= conn.recv(4)

length= struct.unpack('i',length)[0]

operate= (conn.recv(length)).decode('utf-8')

operate_dic=json.loads(operate)

opt= operate_dic['operate']

usr= operate_dic['user']print(opt,usr)

getattr(operate_handler,opt)(conn,usr)

socketserver.TCPServer.allow_reuse_address=True

server= socketserver.ThreadingTCPServer(('127.0.0.1',9000),MyFTP)

server.serve_forever()

operate_handler.pyimportosimportjsonimportstruct

base_path= r'E:\PythonProject\ftp\server\root'

defupload(conn,usr):

fileinfo_len= conn.recv(4)

fileinfo_len= struct.unpack('i',fileinfo_len)[0]

fileinfo= (conn.recv(fileinfo_len)).decode('utf-8')

fileinfo=json.loads(fileinfo)

file_path= os.path.join(base_path,usr,fileinfo['filename'])

file_path=os.path.abspath(file_path)

with open(file_path,'wb') as f:while fileinfo['filesize']:

content= conn.recv(20480)

fileinfo['filesize'] -=len(content)

f.write(content)print('接收完毕')

client.pyimportosimportjsonimportstructimportsocket#发送信息

defmy_send(sk,operate_info):

b_optinfo= (json.dumps(operate_info)).encode('utf-8')

num= struct.pack('i',len(b_optinfo))

sk.send(num)

sk.send(b_optinfo)

sk=socket.socket()

sk.connect(('127.0.0.1',9000))#[登录,注册,退出]

#要进行的操作

operate_info = {'operate':'upload','user':'xiaoming'}

my_send(sk,operate_info)#选择一个文发送到server端

file_path = r'F:\电影\电影\荒野生存.mp4'

#发送文件信息

file_name =os.path.basename(file_path)

file_size=os.path.getsize(file_path)

file_info= {'filename':file_name,'filesize':file_size}

my_send(sk,file_info)#server端接收写入

with open(file_path,'rb') as f:whilefile_size:

content= f.read(20480)

file_size-=len(content)

sk.send(content)print('上传完毕')

sk.close()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值