Python 使用模块模拟并发处理

目录

  • socketserver模块

    • 通过模块实现并发

socketserver模块

我们可以通过socketserver模块来模拟并发的一个状态

接下来我们通过使用socketserver来编写程序模拟并发的一个过程

程序编写:

思路:

  1. 用户注册登录界面
  2. 选择功能
    • 功能的选择

      • 上传
      • 下载
      • 查看文件
      • 删除文件
  3. 对TCP协议粘包的处理

了解粘包:

  • 粘包就是当数据过大或者过小,导致一直存储在内存中。过小导致多次数据同时发送,过大导致数据无法接收完全。

粘包代码:

服务器
import socket
#生成一个socket对象
soc=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#绑定地址跟端口号
soc.bind(('127.0.0.1',8001))
#监听(半连接池的大小),不是连接数
soc.listen(3)
#等着客户端来连接,conn相当于连接通道,addr是客户端的地址
while True:
    print('等待客户端连接')
    conn,addr=soc.accept()    #卡主,如果没有客户端连接,会一直卡在这,当有连接,才继续往下走
    print('有个客户端连接上了',addr)
    while True:
        try:
            data=conn.recv(1024)
            print(data)
            data2=conn.recv(1024)
            print(data2)
            data3=conn.recv(1024)
            print(data3)
        except Exception:

            break
    # 关闭通道
    conn.close()

# 关闭套接字
soc.close()
客服端
import socket

soc=socket.socket()

soc.connect(('127.0.0.1',8001))
while True:
    in_s=input('请输入要发送的数据:')
    soc.send(b'a')
    soc.send(b'b')
    soc.send(b'c')

通过模块实现并发

登录界面代码实现:
import os
import json
import time
import nbK
def register():
    user_dict = {
        'username':None,
        'password':None
    }
    while True:
        print('--------注册---------')
        name = input('请输入你的用户名').strip()
        pwd = input('请输入你要使用的密码:').strip()
        re_pwd = input('确认要使用的密码:').strip()
        if name == 'q' or name == 'Q':
            break
        if os.path.isdir(f'user/{name}'):
            print('用户已经存在')
            continue
        if pwd == re_pwd:
            print('注册成功')
            os.mkdir(f'user/{name}')
            user_dict['username'] = name
            user_dict['password'] = pwd
            with open(f'user_info/{name}.json','w') as fw:
                json.dump(user_dict,fw)
                fw.flush()
            break
def login():
    s = 3
    while True:
        print('--------登录---------')
        name = input('请输入你的用户名')
        pwd = input('请输入你的密码')
        if not os.path.exists(f'user_info/{name}.json'):
            while s>0:
                print(f'\r用户不存在,{s-1}s后跳转到注册界面',end='')
                time.sleep(1)
                s-=1
            print('\n')
            register()
            continue
        with open(f'user_info/{name}.json','r') as fr:
            user_dic = json.load(fr)
        if name == user_dic.get('username') and pwd == user_dic.get('password'):
            print('登录成功')
            nbK.run(name)
            break
        else:
            print('用户名密码不正确')

def run():
    FUN_DIC = {
        '1':register,
        '2':login
    }
    while True:
        print('''
        请选择你的选项
        1——注册
        2——登录
        ''')
        select = input('请输入要选择的功能').strip()
        if not select.isdigit():
            print('请输入正确的选项')
        if not FUN_DIC.get(select):
            print('没有你要选择的功能')
        FUN_DIC[select]()
run()
客户端界面:
import socket
import struct
import os
soc = socket.socket()
soc.connect(('127.0.0.1', 8080))
user_dic = {'username':None}
def uploading():
    soc.send(b'1')
    while True:
        fife_name = input('请输入你要上传的文件名,加后缀哦')
        if fife_name == 'q' or fife_name == 'Q':
            break
        if '.' not in fife_name:
            print('请重新输入你要上传的文件夹名')
            continue
        #传入用户长度
        user_len = struct.pack('i',len(user_dic['username']))
        soc.send(user_len)
        #传入用户名
        soc.send(bytes(user_dic['username'].encode('utf8')))
        #传入文件名长度
        fife_name_len = struct.pack('i',len(fife_name))
        soc.send(fife_name_len)
        # 传入文件名
        soc.send(bytes(fife_name.encode('utf8')))
        with open(fife_name,'rb') as fr:
            byts = fr.read()
        #传入数据长度
        b_len = struct.pack('i',len(byts))
        soc.send(b_len)
        # #传入数据
        soc.send(byts)
        print(f'上传文件{fife_name}成功')

#下载文件
def download():
    soc.send(b'2')
    while True:
        try:
            user_info_list = os.listdir(f'F:\py\9.10并发\\user_name\{user_dic["username"]}')
            for index,name in enumerate(user_info_list):
                print(index+1,name)
            select = input('请选择你要下载的文件')
            if select == 'q' or select == 'Q':
                break
            if len(user_info_list) < int(select):
                print('没有你想要下载的文件')
                continue
            # 传入用户长度
            user_len = struct.pack('i', len(user_dic['username']))
            soc.send(user_len)
            # 传入用户名
            soc.send(bytes(user_dic['username'].encode('utf8')))
            #获取文件名
            fife_name = user_info_list[int(select)-1]
            # 传入文件名长度
            fife_name_len = struct.pack('i', len(fife_name))
            soc.send(fife_name_len)
            # 传入文件名
            soc.send(bytes(fife_name.encode('utf8')))
            # 获取长度信息
            re_len = soc.recv(4)
            # 获取真正的长度
            l = struct.unpack('i', re_len)[0]
            # 进行数据拼接
            count = 0
            date_total = b''
            while count < l:
                if l < 1024:  # 如果接受的数据小于1024 ,直接接受数据大小
                    data = soc.recv(l)
                else:  # 如果接受的数据大于1024
                    if l - count >= 1024:  # 总数据长度-count(目前收到多少,count就是多少) 如果还大于1024  ,在收1024
                        data = soc.recv(1024)
                    else:  # 总数据长度-count(目前收到多少,count就是多少) 如果小于1024,只收剩下的部分就可
                        data = soc.recv(l - count)
                date_total += data
                count += len(data)
            with open(f'{fife_name}', 'wb') as fw:
                fw.write(date_total)
                print(f'下载文件{fife_name}成功')
        except Exception:
            print('请输入要下载的文件序号')
            continue

#删除文件
#########
#偷懒写法#
#########
def delfife():
    while True:
        user_info_list = os.listdir(f'F:\py\9.10并发\\user_name\{user_dic["username"]}')
        for index, name in enumerate(user_info_list):
            print(index + 1, name)
        select = input('请选择你要删除的文件')
        if select == 'q' or select == 'Q':
            break
        if len(user_info_list)<int(select):
            print('没有你想要删除的文件')
        os.remove(f'F:\py\9.10并发\\user_name\{user_dic["username"]}\{user_info_list[int(select)-1]}')
        print('删除成功')

def run(name):
    FUN_DIC = {
        '1': uploading,
        '2': download,
        '3':delfife
    }
    user_dic['username'] = name
    while True:
        print('''
        请选择你需要的功能:
        1-上传文件
        2-下载文件
        3-删除文件
        ''')
        select = input('请输入要选择的功能:').strip()
        if select == 'q' or select == 'Q':
            break
        if not select.isdigit():
            print('请输入正确的选项')
        if not FUN_DIC.get(select):
            print('没有你要选择的功能')
        FUN_DIC[select]()
服务器端
import socketserver
import struct
user_dic = {'username':None}
class Mytcp(socketserver.BaseRequestHandler):
    #重写handle方法
    def handle(self):
        try:
            while True:
                select = self.request.recv(1)
                select = int(select)
                if select == 1:
                    print(self.client_address)
                    while True:
                        #用户名长度
                        age_len = self.request.recv(4)
                        if not age_len:
                            break
                        #用户名真正长度
                        age_l = struct.unpack('i',age_len)[0]
                        user_dic['username'] = self.request.recv(age_l).decode('utf8')
                        #文件名长度
                        fife_len = self.request.recv(4)
                        #文件名真正长度
                        fife_l = struct.unpack('i',fife_len)[0]
                        #读取文件名
                        fife_name = self.request.recv(fife_l).decode('utf8')
                        #获取长度信息
                        re_len = self.request.recv(4)
                        #获取真正的长度
                        l = struct.unpack('i',re_len)[0]
                        #进行数据拼接
                        count = 0
                        date_total =b''
                        while count < l:
                            if l < 1024:  # 如果接受的数据小于1024 ,直接接受数据大小
                                data = self.request.recv(l)
                            else:  # 如果接受的数据大于1024
                                if l - count >= 1024:  # 总数据长度-count(目前收到多少,count就是多少) 如果还大于1024  ,在收1024
                                    data = self.request.recv(1024)
                                else:  # 总数据长度-count(目前收到多少,count就是多少) 如果小于1024,只收剩下的部分就可
                                    data = self.request.recv(l - count)
                            date_total += data
                            count += len(data)
                        with open(f'F:\py\9.10并发\\user_name\{user_dic.get("username")}\{fife_name}','wb') as fw:
                            fw.write(date_total)
                else:
                    while True:
                        # 用户名长度
                        age_len = self.request.recv(4)
                        if not age_len:
                            break
                        # 用户名真正长度
                        age_l = struct.unpack('i', age_len)[0]
                        user_dic['username'] = self.request.recv(age_l).decode('utf8')
                        # 文件名长度
                        fife_len = self.request.recv(4)
                        # 文件名真正长度
                        fife_l = struct.unpack('i', fife_len)[0]
                        # 读取文件名
                        fife_name = self.request.recv(fife_l).decode('utf8')

                        ##打开文件
                        with open(f'F:\py\9.10并发\\user_name\{user_dic["username"]}\{fife_name}','rb') as fr:
                            byts = fr.read()
                            # 传入数据长度
                            b_len = struct.pack('i', len(byts))
                            self.request.send(b_len)
                            # #传入数据
                            self.request.send(byts)

                #第一个参数是用于绑定地址,第二个参数传一个类
                #ThreadingTCPServer自动开线程处理链接状态
        except Exception:
            pass

server = socketserver.ThreadingTCPServer(('127.0.0.1',8080),Mytcp)
    #一直监听
server.serve_forever()

原文地址:https://www.cnblogs.com/ledgua/p/11528787.html

时间: 2024-11-08 20:42:45

Python 使用模块模拟并发处理的相关文章

python get post模拟请求

1.使用get方式时,url类似如下格式: [html] view plaincopy index.jsp?id=100&op=bind GET报问头如下: [html] view plaincopy GET /sn/index.php?sn=123&n=asa HTTP/1.1 Accept: */* Accept-Language: zh-cn host: localhost Content-Type: application/x-www-form-urlencoded Content

Python实现网站模拟登陆

一.实验简介 1.1 基本介绍 本实验中我们将通过分析登陆流程并使用 Python 实现模拟登陆到一个实验提供的网站,在实验过程中将学习并实践 Python 的网络编程,Python 实现模拟登陆的方法,使用 Firefox 抓包分析插件分析网络数据包等知识. 模拟登录可以帮助用户自动化完成很多操作,在不同场合下有不同的用处,无论是自动化一些日常的繁琐操作还是用于爬虫都是一项很实用的技能.本课程通过 Firefox 和 Python 来实现,环境要求如下: Python 库:urllib, ur

python 各模块

01 关于本书 02 代码约定 03 关于例子 04 如何联系我们 1 核心模块 11 介绍 111 内建函数和异常 112 操作系统接口模块 113 类型支持模块 114 正则表达式 115 语言支持模块 12 _ _builtin_ _ 模块 121 使用元组或字典中的参数调用函数 1211 Example 1-1 使用 apply 函数 1212 Example 1-2 使用 apply 函数传递关键字参数 1213 Example 1-3 使用 apply 函数调用基类的构造函数 122

Python _X __all__ 模拟 导入&#39;私有&#39;变量 及其注意点和实例

开头是下划线的变量(如_X): 在特定的情况下,可以吧下划线放在变量名的签名(如_X)可以防止客户端使用from *语句导入模块名时,把其中的那些变量名复制出去:但是下划线不是'私有'声明:仍可以使用其他导入形式看见并且修改这类变量例如使用import __all__(语句) 此外也可以在模块顶层把变量名的字符串列表赋值给变量__all__以达到类似_X命名惯例的隐藏效果:使用此功能,from*语句只会把列在__all__列表中的这些变量名复制出来 __all__是指出要复制的变量名,而_X时指

python 各模块学习

核心模块 1.1. 介绍 1.2. _ _builtin_ _ 模块 1.3. exceptions 模块 1.4. os 模块 1.5. os.path 模块 1.6. stat 模块 1.7. string 模块 1.8. re 模块 1.9. math 模块 1.10. cmath 模块 1.11. operator 模块 1.12. copy 模块 1.13. sys 模块 1.14. atexit 模块 1.15. time 模块 1.16. types 模块 1.17. gc 模块

Python爬虫之模拟登录微信wechat

不知何时,微信已经成为我们不可缺少的一部分了,我们的社交圈.关注的新闻或是公众号.还有个人信息或是隐私都被绑定在了一起.既然它这么重要,如果我们可以利用爬虫模拟登录,是不是就意味着我们可以获取这些信息,甚至可以根据需要来对它们进行有效的查看和管理.是的,没错,这完全可以.本篇博主将会给大家分享一下如何模拟登录网页版的微信,并展示模拟登录后获取的好友列表信息. 微信模拟登录的过程比较复杂,当然不管怎么样方法都是万变不离其宗,我们还是使用fiddler抓包工具来模拟登录的过程.好了,下面让我们一步一

python random模块(14)

random 模块包括返回随机数的函数,可以用于模拟或者任何产生随机输出的程序. 一.random模块常用函数介绍 random.random() — 生成一个从0.0(包含)到 1.0(不包含)之间的随机浮点数: random.uniform(a, b) — 生成一个范围为 a≤N≤b 的随机数,随机数类型是浮点数: random.randint(a, b) — 生成一个范围为 a≤N≤b 的随机数,随机数的类型是整形,注意与random.uniform(a, b)区别: random.ran

python之模块ctypes

# -*- coding: utf-8 -*- #python 27 #xiaodeng #python之模块ctypes import ctypes #ctypes是python的一个外部库,它提供了C兼容的数据类型,并允许调用函数C DLL. #注意事项: #就我个人目前而言,了解该库是提供与C语言数据类型兼容的接口作用即可,不需要深入了解.

python shutil模块总结

shutil.copyfile(src,dst)复制文件,如果存在会覆盖 copymode( src, dst)复制权限 copystat(src, dst)复制访问时间和修改时间和权限 copy(src, dst) 复制文件到一个目录 copy2(src, dst)在copy上的基础上再复制文件最后访问时间与修改时间也复制过来了,类似于cp –p的东西 rmtree(path[, ignore_errors[, onerror]])删除文件 move(src, dst)move文件 copyt