本文实现利用python的socketserver这个强大的模块实现套接字的并发

目录结构如下:

测试文件请放在server_file文件夹里面

server.py

#!/usr/bin/env python
# -*- coding: gbk -*-
# @Version : Python 3.5.2
# @Time : 2018/1/24 10:29
# @Author : Ncp
# @File : server.py
# @Software: PyCharm import json
import time
import hashlib
import struct
import os
from socketserver import * FILE_PATH = os.path.dirname(os.path.abspath(__file__))+'\\server_file' class MYserver(BaseRequestHandler): # 设置一个类,基础BaseRequestHandler这个类
def handle(self): # 这个方法下添加通信功能(和上面创建类一样,这是socketserver的固定模式)
print(self.client_address)
'''
:functions: 使用socketserver的并发套接字,提供客户端下载文件,并对文件进行MD5加密
'''
while True:
try:
data = self.request.recv(1024)
data_recv = data.decode('gbk').split()
if not os.path.exists(FILE_PATH+r'\%s' %data_recv[1]):
self.request.send('file is not found'.encode('gbk'))
continue
else:
data = self.request.send(''.encode('gbk')) # 这里发现小问题,不回复一个信息的话,发送给客户端的包头居然成了没有封装
FILE_SIZE = os.path.getsize(FILE_PATH+r'\%s' %data_recv[1])
with open(FILE_PATH+r'\%s' %data_recv[1],'rb')as f:
hash_file = f.read()
m = hashlib.md5()
m.update(hash_file)
m_hex = m.hexdigest()
file_header = {'filename':data_recv[1],
'filesize':FILE_SIZE,
'md5':m_hex,
'time':time.strftime('%Y-%m-%d-%X',time.localtime())
}
# 包头信息序列化
file_header_dump = json.dumps(file_header)
# 编译成2进制
file_header_bytes = file_header_dump.encode('gbk')
# 封装报头
file_header_struct = struct.pack('i',len(file_header_bytes))
# 发送报头
self.request.send(file_header_struct)
# 发送报文内容
self.request.send(file_header_bytes)
# 发送文件数据
send_size = 0
with open(FILE_PATH+r'\%s' %data_recv[1] , 'rb')as f:
for i in f:
self.request.send(i)
send_size += len(i) # 这里后续可以拓展一个进度或者网速显示功能
except Exception:
self.request.close() if __name__ == '__main__':
server = ThreadingTCPServer(('127.0.0.1',8080),MYserver) # windows下只能开启多线程
server.serve_forever()

client.py

#!/usr/bin/env python
# -*- coding: gbk -*-
# @Version : Python 3.5.2
# @Time : 2018/1/24 10:29
# @Author : Ncp
# @File : client.py
# @Software: PyCharm from socket import *
import os,sys
import hashlib
import struct
import math
import json FILE_PATH = os.path.dirname(os.path.abspath(__file__))+'\\client_file' # 显示下载进度条功能,可以拓展为显示下载速度(提示,因为每次传输4096个字节,那么下载网速为KB/S,1KB个字节=1024B(字节),那么1s传输了多少个字节呢?)
def progress(recvd, total):
fraction = '{:.0%}'.format(recvd / total)
sys.stdout.write('\r[%-30s] %s' % ('#' * int(math.floor(recvd * 30 / total)), fraction))
sys.stdout.flush()
if recvd == total:
sys.stdout.write('\n') # 主函数
def run(ip,addr):
client = socket(AF_INET,SOCK_STREAM)
client.connect((ip,addr))
while True:
user_input = input('>>').strip()
cmd = user_input.split()
if len(cmd) != 2:
print('input format is error please use:get xx')
continue
if cmd[0] == 'get':
client.send(user_input.encode('gbk'))
data = client.recv(1024)
data_recv = data.decode('gbk')
if data_recv == 'file is not found':
print(data_recv)
continue
else:
print('commands is not found')
continue
# 收包头,然后一系列处理
header = client.recv(4)
if not header:break
header_json_len = struct.unpack('i', header)[0]
header_json_bytes = client.recv(header_json_len)
header_josn = header_json_bytes.decode('gbk')
header_dic = json.loads(header_josn)
# 去除包头内容进行下载
print(header_dic)
data_len = header_dic['filesize']
data_file = header_dic['filename']
data_md5 = header_dic['md5']
recv_size = 0
with open(FILE_PATH+r'\%s' %data_file,'wb')as fw:
while recv_size < data_len:
recv_data = client.recv(4096)
recv_size += len(recv_data)
fw.write(recv_data)
progress(recv_size,data_len)
print('Download completion, start validation')
# 收到文件后,读取文件进行加密,看是否与服务端下载的文件一致!
with open(FILE_PATH+r'\%s' %data_file,'rb')as fr:
data_total = fr.read() m = hashlib.md5()
m.update(data_total)
m_hex = m.hexdigest() if m_hex == data_md5:
print('文件验证通过')
else:
print('文件损坏,删除文件')
os.remove(FILE_PATH+r'\%s' %data_file) if __name__ == '__main__':
run('127.0.0.1',8080)

自己可以设置一个多用户登录,然后测试,用户下载同一个文件,分别存入每个用户自己的家目录下面,效果更好。

当然现在也能测试,开启两个客户端同时下载文件。

python利用socketserver实现并发套接字功能的更多相关文章

  1. 基于socketserver模块并发套接字

    1.基于tcp协议 服务端: import socketserverclass MyHandler(socketserver .BaseRequestHandler ): def handle(sel ...

  2. Python 利用字典实现类似 java switch case 功能

    def add(): print('add') def sub(): print('sub') def exit(): print('exit') choice = { '1' : add, '2' ...

  3. 利用Python中SocketServer 实现客户端与服务器间非阻塞通信

    利用SocketServer模块来实现网络客户端与服务器并发连接非阻塞通信 版权声明 本文转自:http://blog.csdn.net/cnmilan/article/details/9664823 ...

  4. 进程池线程池 协程 gvent 单线程实现并发套接字

    1.基于多线程实现套接字服务端支持并发 服务端 from socket import * from threading import Thread def comunicate(conn): whil ...

  5. 如何用Python统计《论语》中每个字的出现次数?10行代码搞定--用计算机学国学

    编者按: 上学时听过山师王志民先生一场讲座,说每个人不论干什么,都应该学习国学(原谅我学了计算机专业)!王先生讲得很是吸引我这个工科男,可能比我的后来的那些同学听课还要认真些,当然一方面是兴趣.一方面 ...

  6. [Python] 利用Django进行Web开发系列(二)

    1 编写第一个静态页面——Hello world页面 在上一篇博客<[Python] 利用Django进行Web开发系列(一)>中,我们创建了自己的目录mysite. Step1:创建视图 ...

  7. python利用or在列表解析中调用多个函数.py

    python利用or在列表解析中调用多个函数.py """ python利用or在列表解析中调用多个函数.py 2016年3月15日 05:08:42 codegay & ...

  8. Python中利用函数装饰器实现备忘功能

    Python中利用函数装饰器实现备忘功能 这篇文章主要介绍了Python中利用函数装饰器实现备忘功能,同时还降到了利用装饰器来检查函数的递归.确保参数传递的正确,需要的朋友可以参考下   " ...

  9. python 利用 ogr 写入shp文件,数据格式

    python 利用 ogr 写入 shp 文件, 定义shp文件中的属性字段(field)的数据格式为: OFTInteger # 整型 OFTIntegerList # 整型list OFTReal ...

随机推荐

  1. python爬虫爬取大众点评并导入redis

    直接上代码,导入redis的中文编码没有解决,日后解决了会第一时间上代码!新手上路,多多包涵! # -*- coding: utf-8 -*- import re import requests fr ...

  2. python2 与python3的变化

    1 写文件如果是bytes类型的话,打开文件 open参数设置为wb 2 python2 默认包import是相对路径,python3是绝对路径 3 python3的dict没有has_key方法,用 ...

  3. 搭建redis cluster

    1  下载 redis安装包 tar zxvf redis-3.0.2.tar.gz cd redis-3.0.2/ make make install 2安装ruby sudo apt-get in ...

  4. Fiddler 抓包https配置 提示creation of the root certificate was not successful 证书安装不成功

    在使用Fiddler抓包时,我们有时需要抓https协议的包,这种需要配置一下 开启监控https才可以 首先 找到Tools——>Options 在弹出的菜单中 选择https项  勾选捕捉h ...

  5. 树上操作[HAOI 2015]

    树链剖分裸题: 树剖点这里:传送门 代码: #include<bits/stdc++.h> #define sight(c) ('0'<=c&&c<='9') ...

  6. python实现二分查找算法

    二分查找算法也成为折半算法,对数搜索算法,一会中在有序数组中查找特定一个元素的搜索算法.搜索过程是从数组中间元素开始的 如果中间元素正好是要查找的元素,则搜索过程结束:如果查找的数大于中间数,则在数组 ...

  7. Node.js 蚕食计划(一)—— 模块化编程

    众所周知,Node.js 的出现造就了全栈工程师,因为它让 JavaScript 的舞台从浏览器扩大到了服务端 而 Node.js 的强大也得益于它庞大的模块库,所以学习 Node.js 第一步还得从 ...

  8. 基于MongoDb官方C#驱动封装MongoDbCsharpHelper类(CRUD类)

    近期工作中有使用到 MongoDb作为日志持久化对象,需要实现对MongoDb的增.删.改.查,但由于MongoDb的版本比较新,是2.4以上版本的,网上已有的一些MongoDb Helper类都是基 ...

  9. git for windows上传项目到github

    软件:git for windows 账户:github账户 1.第一步创建自己的github账号,并创建自己的project,创建完毕之后url如下 https://github.com/ft110 ...

  10. eclipse常用快捷设置

    1.代码自动提示 在我们忘记方法名或者想偷懒时,代码自动提示很管用.不过Eclipse默认是输入"."后才会出现包或类成员的提示,也就意味着我们必须先输入一个完整的类名,提示才能出 ...