当前位置: 首页 > news >正文

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

1、文件上传/下载

  学习了socket套接字,我们现在可以写一个文件上传/下载的程序,如下示例:

 

 

  分析上边代码,我们发现,client发送上传文件相关信息的字典序列化之后,server又给client发送了一个状态码,然后client才开始上传文件数据,思考一下如果不发送状态码,直接发送文件数据且避免黏包现象发生该怎么写?没错!可以用struct模块解决,如下示例:

  struct(四chua科特)打包如何用呢,简单写一下:

import struct
num = 156
#将int类型的数据打包成4个字节的数据
num_stru = struct.pack('i',num)                    #pack(爬可)  
print(len(num_stru))          #他的长度四个字节
print(num_stru)              
print('11111111111111111111111111111111')

#在通过int类型解包,将前面打包的数据解包成打包之前的int数据
num2 = struct.unpack('i',num_stru) #解包出来是个元组        unpack(嗯牌可)
print(num2)#(156,)
print(num2[0])

  服务端代码:

 

  客户端代码:

 

 

  分析上面的代码,看看是如何避免黏包现象的?client先给server发送字典的长度的pack包,再发送字典,再发送文件数据,server先接收4字节的pack包,进行unpack后得到字典长度,再根据字典长度接收字典,最后再循环接收文件数据。并且该示例还进行了MD5算法来进行文件一致性校验。

二、socketserver(并发)(骚k特色我)

  通过这两天学习socket套接字,我们发现在写服务端和客户端的时候,在建立连接之前总是要写一些固定的重复代码来,比如socket.socket()(创建套接字对象)、bind()、acecept()等等,学习了socketserver(并发)之后,就可以少写一些代码,并且实现并发,如下示例:

 服务端:

import socketserver                            

#1 定义一个类
class MyServer(socketserver.BaseRequestHandler): #2 类里面继承socketserver.BaseRequestHandler  #BaseRequestHandler贝斯蕊快四特汉得了
    # 3 类里面定义一个handle方法,handle名称不能变
    def handle(self):    #handle(汉得了)
        while 1:
        # self.request      #conn链接通道                              request(蕊快死特)
            from_client_data = self.request.recv(1024).decode('utf-8')
            print(from_client_data)
            server_input = input('明巍sb说>>>')
            self.request.send(server_input.encode('utf-8'))
        # self.request.close()
if __name__ == '__main__':
    #服务端的IP地址和端口
    ip_port = ('127.0.0.1',8001)
    socketserver.TCPServer.allow_reuse_address = True    #允许地址重用
    #绑定IP地址和端口,并且启动我定义的上面这个类
    server = socketserver.ThreadingTCPServer(ip_port,MyServer)
    #永久的给我执行下去
    server.serve_forever()

客户端:

import socket

tcp_client = socket.socket()
server_ip_port = ('127.0.0.1',8001)
tcp_client.connect(server_ip_port)
while 1:
    client_msg = input('大阳哥>>>')
    tcp_client.send(client_msg.encode('utf-8'))
    from_server_msg = tcp_client.recv(1024).decode('utf-8')
    print(from_server_msg)

三、解读python中socketserver源码

  结合下图中类的继承关系和类中的方法,分析socketserver代码的执行过程:

  a、初始化相关过程:server = socketserver.ThreadingTCPServer(('127.0.0.1',8800),Myserver)

    (1)TCPServer类中的__init__方法:

                     TCPServer类中主动执行BaseServer类中的__init__ 方法(把自己创建的Myserver类传参);

                     创建socket.socket()对象;

                     server_bind() -- 在TCPServer类中执行了socket.bind(self.server_address)

                     server_activate() -- 在TCPServer类中执行了socket.listen(5)

    (2)BaseServer类中的__init__ 方法:

      将参数server_address(ip地址和端口号)赋值给了self.server_address;

                     将形参RequestHandlerClass(实参是我们自己创建的Myserver类)赋值给了self.RequestHandlerClass;

 

  b、执行serve_forever的相关代码:

    (1)执行BaseServer类中的serve_forever()方法:

      注意看if ready后边的那句self._handle_request_noblock(),其他先忽略;

    (2)执行BaseServer中的_handle_request_noblock(self)方法:

      看第一个try中request,client_address = self.get_request(),

        TCPServer中有get_request()方法,方法中是return self.socket.accept(),即等待连接;

                     再看第二个try中的self.process_request(request,client_address)

     (3)连接成功之后拿到了request(即conn)和client_address(即addr)再去执行BaseServer类中的.process_request方法;

        创建线程,执行方法process_request_thread()

 

    (4)执行ThreadingMixIn 类中的process_request_thread(self, request, client_address)方法:

                     看try中self.finish_request(request,client_address)

    (5)执行BaseServer中的finish_request(request,client_address)方法:

      此时还记得RequestHandlerClass这个参数吗?正是我们执行BaseServer中__init__方法时传过来的自己创建的类Myserver,类() 即实例化一个Myserver对象,并且传了两个参数(conn,addr),但是我们自己写的Myserver类中没有__init__方法,所以执行Myserver父类BaseRequestHandler类中的__init__方法,并且带了每个连接的线程的conn和addr:

     (6)执行BaseRequestHandler中的__init__方法:

      此时self是Myserver类的对象,所以优先去执行Myserver类中handle方法。

 附录:以下是各类的继承关系以及类中成员方法:

   

 

 

 

 

转载于:https://www.cnblogs.com/xihuanniya/p/9811222.html

相关文章:

  • sass笔记
  • 附加数据库时出错问题处理
  • 整理:手机端弹出提示框,使用的bootstrap中的模态框(modal,弹出层),比kendo弹出效果好...
  • Hdoj 1087.Super Jumping! Jumping! Jumping!
  • docker集群演练
  • UVA11090 Going in Cycle!!
  • 继承派生 属性查找
  • 针对shiro框架authc拦截器认证成功后跳转到根目录,而非指定路径问题
  • day06 再谈编码
  • React Native搭建开发环境 之 --走过的坑
  • noip2018复习计划啊
  • Linux之iptables(一、防火墙的概念)
  • 基于版本一致性算法
  • golang中的mutex锁
  • python中的__str__ __name__ 和__call__方法
  • [PHP内核探索]PHP中的哈希表
  • 【css3】浏览器内核及其兼容性
  • 30秒的PHP代码片段(1)数组 - Array
  • Angular js 常用指令ng-if、ng-class、ng-option、ng-value、ng-click是如何使用的?
  • angular2开源库收集
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • electron原来这么简单----打包你的react、VUE桌面应用程序
  • js操作时间(持续更新)
  • passportjs 源码分析
  • Python 反序列化安全问题(二)
  • Python学习之路13-记分
  • Rancher如何对接Ceph-RBD块存储
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 前嗅ForeSpider中数据浏览界面介绍
  • 再次简单明了总结flex布局,一看就懂...
  • 你对linux中grep命令知道多少?
  • 阿里云重庆大学大数据训练营落地分享
  • #162 (Div. 2)
  • (六)vue-router+UI组件库
  • (牛客腾讯思维编程题)编码编码分组打印下标(java 版本+ C版本)
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (转)http-server应用
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转载)Linux网络编程入门
  • (转载)虚幻引擎3--【UnrealScript教程】章节一:20.location和rotation
  • .mkp勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET Core 2.1路线图
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET Framework 4.6.2改进了WPF和安全性
  • .NET Reactor简单使用教程
  • .Net Redis的秒杀Dome和异步执行
  • .NET 反射 Reflect
  • .NET 设计模式—适配器模式(Adapter Pattern)
  • .net专家(张羿专栏)
  • @SuppressLint(NewApi)和@TargetApi()的区别
  • [ IO.File ] FileSystemWatcher
  • []指针
  • [ABC294Ex] K-Coloring
  • [CentOs7]图形界面