from socket import *
import hmac,os secret_key=b'linhaifeng bang bang bang'
def conn_auth(conn):
'''
认证客户端链接
:param conn:
:return:
'''
print('开始验证新链接的合法性')
msg=os.urandom(32)
conn.sendall(msg)
h=hmac.new(secret_key,msg)
digest=h.digest()
respone=conn.recv(len(digest))
return hmac.compare_digest(respone,digest) def data_handler(conn,bufsize=1024):
if not conn_auth(conn):
print('该链接不合法,关闭')
conn.close()
return
print('链接合法,开始通信')
while True:
data=conn.recv(bufsize)
if not data:break
conn.sendall(data.upper()) def server_handler(ip_port,bufsize,backlog=5):
'''
只处理链接
:param ip_port:
:return:
'''
tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(backlog)
while True:
conn,addr=tcp_socket_server.accept()
print('新连接[%s:%s]' %(addr[0],addr[1]))
data_handler(conn,bufsize) if __name__ == '__main__':
ip_port=('127.0.0.1',9999)
bufsize=1024
server_handler(ip_port,bufsize)

服务端

from socket import *
import hmac,os secret_key=b'linhaifeng bang bang bang'
def conn_auth(conn):
'''
验证客户端到服务器的链接
:param conn:
:return:
'''
msg=conn.recv(32)
h=hmac.new(secret_key,msg)
digest=h.digest()
conn.sendall(digest) def client_handler(ip_port,bufsize=1024):
tcp_socket_client=socket(AF_INET,SOCK_STREAM)
tcp_socket_client.connect(ip_port) conn_auth(tcp_socket_client) while True:
data=input('>>: ').strip()
if not data:continue
if data == 'quit':break tcp_socket_client.sendall(data.encode('utf-8'))
respone=tcp_socket_client.recv(bufsize)
print(respone.decode('utf-8'))
tcp_socket_client.close() if __name__ == '__main__':
ip_port=('127.0.0.1',9999)
bufsize=1024
client_handler(ip_port,bufsize)

客户端

基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环

socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题)

server类:

request类:

查找属性的顺序:ThreadingTCPServer->ThreadingMixIn->TCPServer->BaseServer

  1. 实例化得到ftpserver,先找类ThreadingTCPServer的__init__,在TCPServer中找到,进而执行server_bind,server_active
  2. 找ftpserver下的serve_forever,在BaseServer中找到,进而执行self._handle_request_noblock(),该方法同样是在BaseServer中
  3. 执行self._handle_request_noblock()进而执行request, client_address = self.get_request()(就是TCPServer中的self.socket.accept()),然后执行self.process_request(request, client_address)
  4. 在ThreadingMixIn中找到process_request,开启多线程应对并发,进而执行process_request_thread,执行self.finish_request(request, client_address)
  5. 上述四部分完成了链接循环,本部分开始进入处理通讯部分,在BaseServer中找到finish_request,触发我们自己定义的类的实例化,去找__init__方法,而我们自己定义的类没有该方法,则去它的父类也就是BaseRequestHandler中找....

源码分析总结:

基于tcp的socketserver我们自己定义的类中的

  1.   self.server即套接字对象
  2.   self.request即一个链接
  3.   self.client_address即客户端地址

基于udp的socketserver我们自己定义的类中的

  1.   self.request是一个元组(第一个元素是客户端发来的数据,第二部分是服务端的udp套接字对象),如(b'adsf', <socket.socket fd=200, family=AddressFamily.AF_INET, type=SocketKind.SOCK_DGRAM, proto=0, laddr=('127.0.0.1', 8080)>)
  2.   self.client_address即客户端地址
import socketserver
import struct
import json
import os
class FtpServer(socketserver.BaseRequestHandler):
coding='utf-8'
server_dir='file_upload'
max_packet_size=1024
BASE_DIR=os.path.dirname(os.path.abspath(__file__))
def handle(self):
print(self.request)
while True:
data=self.request.recv(4)
data_len=struct.unpack('i',data)[0]
head_json=self.request.recv(data_len).decode(self.coding)
head_dic=json.loads(head_json)
# print(head_dic)
cmd=head_dic['cmd']
if hasattr(self,cmd):
func=getattr(self,cmd)
func(head_dic)
def put(self,args):
file_path = os.path.normpath(os.path.join(
self.BASE_DIR,
self.server_dir,
args['filename']
)) filesize = args['filesize']
recv_size = 0
print('----->', file_path)
with open(file_path, 'wb') as f:
while recv_size < filesize:
recv_data = self.request.recv(self.max_packet_size)
f.write(recv_data)
recv_size += len(recv_data)
print('recvsize:%s filesize:%s' % (recv_size, filesize)) ftpserver=socketserver.ThreadingTCPServer(('127.0.0.1',8080),FtpServer)
ftpserver.serve_forever()

FtpServer

import socket
import struct
import json
import os class MYTCPClient:
address_family = socket.AF_INET socket_type = socket.SOCK_STREAM allow_reuse_address = False max_packet_size = 8192 coding='utf-8' request_queue_size = 5 def __init__(self, server_address, connect=True):
self.server_address=server_address
self.socket = socket.socket(self.address_family,
self.socket_type)
if connect:
try:
self.client_connect()
except:
self.client_close()
raise def client_connect(self):
self.socket.connect(self.server_address) def client_close(self):
self.socket.close() def run(self):
while True:
inp=input(">>: ").strip()
if not inp:continue
l=inp.split()
cmd=l[0]
if hasattr(self,cmd):
func=getattr(self,cmd)
func(l) def put(self,args):
cmd=args[0]
filename=args[1]
if not os.path.isfile(filename):
print('file:%s is not exists' %filename)
return
else:
filesize=os.path.getsize(filename) head_dic={'cmd':cmd,'filename':os.path.basename(filename),'filesize':filesize}
print(head_dic)
head_json=json.dumps(head_dic)
head_json_bytes=bytes(head_json,encoding=self.coding) head_struct=struct.pack('i',len(head_json_bytes))
self.socket.send(head_struct)
self.socket.send(head_json_bytes)
send_size=0
with open(filename,'rb') as f:
for line in f:
self.socket.send(line)
send_size+=len(line)
print(send_size)
else:
print('upload successful') client=MYTCPClient(('127.0.0.1',8080)) client.run()

FtpClient

认证客户端的链接与socketserver实现并发的更多相关文章

  1. 验证客户端的链接合法性和socketserver模块实现并发

    本节内容: 1.验证客户端的链接合法性 2.socketserver模块实现并发 一.验证客户端的链接合法性 首先,我们来探讨一下,什么叫验证合法性, 举个例子:有一天,我开了一个socket服务端, ...

  2. socket认证客户端链接合法性

    服务器端: #_*_coding:utf-8_*_ __author__ = 'Linhaifeng' from socket import * import hmac,os secret_key=b ...

  3. 36、IO模型与socketserver实现并发

    特别声明本随笔copy于egon(林海峰). 一 IO模型介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous) IO和异步(asynchronou ...

  4. socketserver实现并发

    socketserver实现并发原理:给每一个前来链接的客户端开启一个线程执行通信.也就是给每一个连接“配备”了一个管家. 下面用一个简单的示例来演示socketserver实现并发(一个服务端,两个 ...

  5. python之socketserver实现并发

    python之socketserver实现并发 服务端 import socketserver #socketserver模块是用来实现并发 # 我们自己的类里一定要继承socketserver.Ba ...

  6. 文件上传下载、socketserver(并发)、解读socketserver源码

    1.文件上传/下载 学习了socket套接字,我们现在可以写一个文件上传/下载的程序,如下示例: 分析上边代码,我们发现,client发送上传文件相关信息的字典序列化之后,server又给client ...

  7. 基于socketserver实现并发

    基于tcp的套接字,关键就是两个循环,一个链接循环,一个通信循环 socketserver模块中分两大类:server类(解决链接问题)和request类(解决通信问题) 一.分析socketserv ...

  8. 网络编程----socketserver多并发实现、FTP上传多并发、udp协议套接字多并发

    一.socketserver多并发                                                              基于tcp的套接字,关键就是两个循环,一个 ...

  9. Python之利用socketserver实现并发

    socketserver这个模块是利用IO多路复用以及多线程实现并发的,可以让服务器同时建立多个链接 原理如图 我们这样更改服务器代码 import socketserver '''需要先写上一个类继 ...

随机推荐

  1. SOJ--Zig-Zag

    Zig-Zag 在图形图像处理中经常须要将一个二维的图像矩阵转化为一维的向量.二维化一维的过程实际上就是将二维数组的元素按某种顺序构成一维数组. 一种经常使用的序列叫"Zig-Zag&quo ...

  2. HDOJ 4251 The Famous ICPC Team Again

    划分树水题..... The Famous ICPC Team Again Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 3276 ...

  3. Android音频: 怎样使用AudioTrack播放一个WAV格式文件?

    翻译 By Long Luo 原文链接:Android Audio: Play a WAV file on an AudioTrack 译者注: 1. 因为这是技术文章,所以有些词句使用原文,表达更准 ...

  4. 动态生成表格的每一行的操作按钮如何获取当前行的index

    for(var i=0; i<10; i++) { $("#tableList").append( $("<tr>").append( $(& ...

  5. Python爬虫(二十三)_selenium案例:动态模拟页面点击

    本篇主要介绍使用selenium模拟点击下一页,更多内容请参考:Python学习指南 #-*- coding:utf-8 -*- import unittest from selenium impor ...

  6. 以通配符(%)开始的like字符串,走索引

    在对oracle的SQL优化过程中经常会遇到[like'%abc']破坏索引的问题,但是如果真有此类需求,该如何在不破坏索引的基础上进行查询呢. [sql] view plain copy sys@m ...

  7. 《算法 (第4版)》【PDF】下载

    <算法 (第4版)>[PDF]下载链接: https://u253469.ctfile.com/fs/253469-231196349 (第4版)>[PDF]"  TITL ...

  8. LeetCode #1 TwoSum

    Description Given an array of integers, return indices of the two numbers such that they add up to a ...

  9. php面向对象4

    成员属性 基本介绍 成员属性是类的一个组成部分,一般是基本数据类型,也可以是复合类型,资源类型.比如 public $age;就是成员属性 说明 ①成员属性可以是php的任何数据类型(int, flo ...

  10. Angular 报错 Can't bind to 'formGroup' since it isn't a known property of 'form'

    错误描述 当form表单加FormGroup属性时报错 Can't bind to 'formGroup' since it isn't a known property of 'form' < ...