一、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

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

  1. SocketServer模块,hmac模块验证client合法性

    hmac模块: 1.模块初识: import hmac # h = hmac.new() #括号里要给它连个bytes类型,一个是自定义的secret_key,一个是你想进行加密的bytes # 密文 ...

  2. python之路----验证客户端合法性

    验证客户端链接的合法性 import os import hmac import socket secret_key = b'egg' sk = socket.socket() sk.bind(('1 ...

  3. python 全栈开发,Day36(作业讲解(大文件下载以及进度条展示),socket的更多方法介绍,验证客户端链接的合法性hmac,socketserver)...

     先来回顾一下昨天的内容 黏包现象 粘包现象的成因 : tcp协议的特点 面向流的 为了保证可靠传输 所以有很多优化的机制 无边界 所有在连接建立的基础上传递的数据之间没有界限 收发消息很有可能不完全 ...

  4. Python之socketserver模块和验证客户端链接的合法性

    验证客户端链接的合法性 分布式系统中实现一个简单的客户端链接认证功能 #_*_coding:utf-8_*_ from socket import * import hmac,ossecret_key ...

  5. Socket编程服务器和客户端【重要】

    socket编程服务器和客户端[重要] 看过很多网上大神们写的socket,无论复杂或是简洁,感觉对于新手都不是很友好,写的步骤和过程描述得不是很清晰,最近又想起来要写一写,就当做个笔记吧~ 不多说! ...

  6. C# Socket服务端与客户端通信(包含大文件的断点传输)

    步骤: 一.服务端的建立 1.服务端的项目建立以及页面布局 2.各功能按键的事件代码 1)传输类型说明以及全局变量 2)Socket通信服务端具体步骤:   (1)建立一个Socket   (2)接收 ...

  7. java ocsp校验_Nginx使用OCSP验证客户端证书

    此前,Nginx只支持OSCP验证服务器证书. 目前,Nginx 1.19.0+已经支持使用OSCP验证客户端证书:https://trac.nginx.org/nginx/ticket/1534 有 ...

  8. linux软件不能通过验证,Linux上安装软件之前先验证软件包合法性

    以前有为Linux专家说过一句很经典的话"小即是美".这句话一针见血的道出了Linux操作系统的设计特点.Linux操作系统跟微软操作系统不同,它都是一个个相对独立的软件所构成的一 ...

  9. 【★更新★】高性能 Windows Socket 服务端与客户端组件(HP-Socket v2.0.1 源代码及测试用例下载)...

    HP-Socket 以前为某大型通信项目开发了一套通用 Windows Socket TCP 底层通信组件,组件代号为 HP-Socket.现在把 HP-Socket 的所有代码向大众公开,希望能对大 ...

最新文章

  1. 控制显示隐藏_大众发动机控制单元隐藏功能刷写
  2. 007_JavaScript关键字和保留字
  3. SpringMVC拦截器-快速入门详解(应用)
  4. Ollydbg中F8的Bug
  5. [kuangbin带你飞]专题五 并查集 A - Wireless Network
  6. Windows 10 开发日记(二)-- 手势顺序调研
  7. struts2第一个程序的详解(配图)
  8. 微信公众号支付失败的各种原因
  9. 云服务商拿来主义或大限将至,Elastic 表示将变更开源许可协议并进行诉讼
  10. android模拟走路,走路模拟器官网版
  11. bat——批量删除文件文件夹
  12. 又要数数小绵羊(四刷) kkmd66
  13. 成都盛铭轩:直通车小知识
  14. AndroidStudio恢复误删文件
  15. 嵌入式系统与通用计算机系统的区别,嵌入式操作系统和通用计算机系统两者有什么不同之处...
  16. 单价多少元一千克在c语言中怎么表示_小学三年级数学《克和千克的认识》说课稿范文...
  17. Kafka源码阅读-Controller(二)管理brokers
  18. 数字化转型中的大数据治理架构
  19. C++常见十六进制数组转换char数组方法
  20. AssetBundle-AssetBundle Brower Tool

热门文章

  1. centos桥接模式怎么联网_今日回收 | 互联网+废品回收模式是怎么兴起的呢?
  2. 深度学习pytorch--线性回归(三)
  3. php怎样完成批量审核,CMS_DedeCMS 批量取消审核文档的实现方法,今天修改了几个地方的代码 实 - phpStudy...
  4. g30u盘启动 中科曙光1620_I620-G30
  5. 名词解释多媒体计算机,多媒体-名词解释及填空
  6. python采用函数编程模式_浅谈Python 函数式编程
  7. php拼接多个insert,php – 将多个INSERTS分成一个表和多个表
  8. 宝塔面板php降级,宝塔面板6.8.8降级到5.9.1的方案教程
  9. 什么是RS232/RS485转换器?
  10. 【渝粤教育】国家开放大学2018年秋季 1344T金融风险管理 参考试题