socketserver和socket的补充(验证客户端合法性)

一、socket的补充
1、参数
socket.socket(family=AF_INET,type=SOCK_STREAM,proto=0,fileno=None)
参数说明:
family
地址系列应为AF_INET(默认值ipv4),AF_INET6(ipv6),AF_UNIX,AF_CAN或AF_RDS。
(AF_UNIX 域实际上是使用本地 socket 文件来通信)
type
套接字类型应为SOCK_STREAM(默认值,tcp协议),SOCK_DGRAM(udp协议),SOCK_RAW或其他SOCK_常量之一。
SOCK_STREAM 是基于TCP的,有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料传送。 
SOCK_DGRAM 是基于UDP的,无保障的面向消息的socket,多用于在网络上发广播信息。
proto
协议号通常为零,可以省略,或者在地址族为AF_CAN的情况下,协议应为CAN_RAW或CAN_BCM之一。
fileno
如果指定了fileno,则其他参数将被忽略,导致带有指定文件描述符的套接字返回。
与socket.fromfd()不同,fileno将返回相同的套接字,而不是重复的。
这可能有助于使用socket.close()关闭一个独立的插座。



2、socket更多方法介绍
服务端套接字函数
s.bind()   绑定(主机,端口号)到套接字
s.listen()开始TCP监听
s.accept()被动接受TCP客户的连接,(阻塞式)等待连接的到来
客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex()connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收TCP数据
s.recvfrom()接收UDP数据
 
s.send() 发送TCP数据
s.sendall()发送TCP数据
s.sendto() 发送UDP数据
 
s.getpeername()连接到当前套接字的远端的地址(client地址)
s.getsockname() 当前套接字的地址(server地址)
 
s.setsockopt()设置指定套接字的参数(端口复用)
s.getsockopt() 返回指定套接字的参数
 
s.close()关闭套接字
面向锁的套接字方法
s.setblocking()设置套接字的阻塞(True)与非阻塞模式(False)  *****
s.settimeout()设置阻塞套接字操作的超时时间  accept()的等待时间
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
 

 

3、验证客户端合法性
场景:如果别人知道了你的服务器的IP,那么他就可以使用扫端口的方式去连接上你的服务器,因为我们都知道,端口的范围是0-65535,
那么别人知道了你的服务器IP后,就可以循环扫这些端口,就可以连接上你的服务,你服务器所进行的一些操作,比如一些数据的传输,
就会被别人所获取,所以这个时候就需要验证客户端的合法性。


代码 服务端:
import os import hmac import socketdef auth(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('合法的连接') # 对比成功可以继续通信return Trueelse:print('不合法连接') # 不成功return Falsesecret_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() if auth(conn):msg = conn.recv(1024) # True正常的和client端进行沟通print(msg.decode('utf-8'))conn.close() else:conn.close() # False 直接关闭和这个客户端的连接 sk.close()客户端: import hmac import socketdef auth(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可以跟多个客户端同时连接(并发)。服务端: import socketserver # 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()客户端: import socket sk = socket.socket() sk.connect(('127.0.0.1',8888)) while True:ret = sk.recv(1024)print(ret.decode('utf-8'))sk.send(b'hiworld') sk.close()解释为什么一定要重写handler方法: Myserver这个类没有__init__方法,那么它就会去继承使用父类BaseRequestHandler的__init__方法 看看BaseRequestHandler源码: class BaseRequestHandler: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()def setup(self):passdef handle(self):passdef finish(self):pass总结: 也就是说,子类继承了父类的__init__方法,这个方法里面已经取到了客户端的对象conn,和地址addr, 并且初始化的时候调用了handler方法,但是父类的handler方法并没有实现任何功能,所以子类应该重写handler方法便于与客户端交互。实例:上传文件server.pyimport json import struct import socketserver import operate_handlerclass MyFTP(socketserver.BaseRequestHandler):def handle(self):conn = self.requestlength = 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.pyimport os import json import structbase_path = r'E:\PythonProject\ftp\server\root'def upload(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.pyimport os import json import struct import socket# 发送信息 def my_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:while file_size:content = f.read(20480)file_size -= len(content)sk.send(content) print('上传完毕') sk.close()

 

转载于:https://www.cnblogs.com/Zzbj/p/9664404.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/352770.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Spring Boot和Spring Security验证JWT

对于我当前的项目,我将使用Spring Boot设置REST API (最有可能使用BoxFuse运行)。 为了能够使用API​​端点,应用程序将检查传入的请求是否具有较早提供的有效JWT令牌 (由我信任的API服务提供)。 为了实现…

怎么查看linux文件夹下有多少个文件

ls | wc -w是查看有多少个文件及文件夹ls | wc -c这个查看目录下多少个文件. 使用wc命令 具体通过wc --help 可以查看。如:wc -l filename 就是查看文件里有多少行 wc -w filename 看文件里有多少个word。 wc -L filename 文件里最长的那一行是多少个字…

[转]xargs详解

为什么要用xargs,问题的来源 在工作中经常会接触到xargs命令,特别是在别人写的脚本里面也经常会遇到,但是却很容易与管道搞混淆,本篇会详细讲解到底什么是xargs命令,为什么要用xargs命令以及与管道的区别。为什么要用x…

计算机桌面图片怎么设置大小,怎么设置桌面壁纸大小

很多人都知道怎麽设置电脑桌面,可真正找到适合自己屏幕的可能很少,图片或大或小,小编为大家分享了设置桌面壁纸大小的方法,下面大家跟着小编一起来了解一下吧。设置桌面壁纸大小方法先查看自己电脑屏幕分辨率,方法&…

html5 clip,canvas中使用clip()函数裁剪方法

未使用裁剪绘制一个圆*{margin:0;padding:0;}html,body{width:100%;height:100%;overflow:hidden;background-color:#AFAFAF;}varcanvasdocument.getElementById(canvas),contextcanvas.getContext(2d);canvas.widthdocument.body.clientWidth;canvas.heightdocument.body.clie…

linux中管道符的简单使用

管道符,可以把两条命令连起来,具体来说有两种应用,如下: 1. 例如: ps aux | grep "media" 在 ps aux中的結果中查找media。 2. 例如: find . -name "*.cpp" | xargs grep "cl…

51 nod 1522 上下序列——序列dp

题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId1522 很好的思想。考虑从小到大一对一对填数,这样也能对它的大小限制做一些操作了。 因为从小到大,所以只能全填在左边、全填在右边、两边各填一个。记录左边填到了哪个位…

spring tiles_Spring MVC 3模板和Apache Tiles

spring tiles对于任何Web应用程序,有效的设计考虑因素是使用模板引擎(或工具),并且由于具有Spring的“可插拔”特性,集成模板机制(例如Apache Tiles)确实要容易得多。 在这篇简单的文章中&#…

流程图用计算机if怎么写,if语句流程图

使用if语句实现单分支、两分支和使用switch语句实现多分支的程序程序1、if 语句有下面三种情况。第一种,条件成立就做。不成立就不做。if (条件)程序endif第二种,条件成立做“程序一”,不成立做“程序二”。不管条件成不成立都做。if (条件)程…

CENTOS 7 踢用户_从零学ELK系列(三):Centos安装Docker(超详细图文教程)

CSDN博客地址(关注,点赞)人工智能推荐GitHub(Star,Fork,Watch)【前言】为了更加真实的模拟生产部署环境,不仅需要Linux环境支持,而且ELK需要在不同的机器上部署;再重新装几台虚拟机&…

boost开发指南

C确实很复杂,神一样的0x不知道能否使C变得纯粹和干爽? boost很复杂,感觉某些地方有过度设计和太过于就事论事的嫌疑,对实际开发工作的考虑太过于理想化。学习boost本身就是一个复杂度,有魄力在项目中广泛采用boost复杂…

打游戏提示计算机丢失,Windows7电脑运行某游戏提示“计算机丢失mxvcp120.dll”怎么办...

许多用户都很喜欢在windows7系统中玩一些游戏,而在玩游戏的时候难免碰上一些错误提示,比如最近有windows7系统用户发现在运行某款游戏的时候,提示“计算机丢失mxvcp120.dll”,导致无法继续玩游戏,要怎么解决呢&#xf…

如何开发一个可运维系统的一点体会

本文来自网易云社区作者:施勇我们在开发一个复杂系统的时候,常常会强调服务化、模块化、松散耦合等要求以达到高可用、高可靠及高性能等目的;比较少的人会考虑到系统的方便部署配置和运维,至少是在刚开始设计系统的时候很少考虑到…

工程勘察设计收费标准2002修订版_全过程工程咨询收费模式超全解析

国内全过程工程咨询试点方案中收费标准比较全过程工程咨询是近两年提出的新的工程建设组织模式,它的管理机制、运行方式还处于探索阶段。各试点省、市相继发布了全过程工程咨询试点工作方案,对全过程工程咨询收费问题进行了积极探索。笔者整理了部分省市…

Java / Web项目中的NPM模块Browser-Sync

Browser-Sync是一个方便的基于Node.js的NPM模块,可用于更快的Web开发。 浏览器同步可在许多设备之间同步文件更改和交互。 最重要的功能是实时重新加载。 我们也可以在Java / Web项目中使用Browser-Sync。 Cagatay Civici创造了一个伟大的 视频教程如何在PrimeFace…

设置vs2008代码区的背景色

编写程序、调试代码时,是不是感觉文字的白色背景有些刺眼呢?vs2008 给我们提供了改变背景色的功能。 依次展开:工具->选项->环境->字体和颜色,可以看到下图所示设置框。 首先,在图中标记的“显示项”一栏选择…

bzoj3277 串 (后缀数组+二分答案+ST表)

常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在…

微型计算机实验报告温度控制,单片机、可编程控制器实验教学大纲.doc

单片机、可编程控制器实验教学大纲.doc单片机、可编程控制器实验教学大纲 一、实验课的性质与任务 本实验课是在学生学完单片机原理与应用课程之后,为巩固提高所学知识,而安排的一次综合设计实验。通过本实验使学生将所学的单片机硬件结构、工作原理、编…

电脑word在哪_Word论文里的公式怎么编辑?这4个小工具帮你一分钟搞定!

临近毕业时,不少小可爱都在为论文头秃!搜索并下载论文,论文排版,论文查重,这些我们之前已经写过相关文章啦!Tools指南推荐搜索论文论文排版论文查重论文网站今天,再来给大家分享一个写论文时经常…

RTree算法及介绍

空间索引是对存储在介质上的数据位置信息的描述,用来提高系统对数据获取的效率。GIS涉及的各种海量复杂数据存储于外存,如果对磁盘上的数据的位置不加以记录和组织,每查询一个数据项都要扫描整个数据文件,则这种访问磁盘的代价将严…