[TOC]
模拟ftp中的get和put命令,实现文件的上传和下载,用法了`struct`模块和`socket`模块
## 服务端代码
```
import socket
import subprocess
import struct
import json
import os
share_dir=r'/Users/XXX/server/share'
def get(conn,cmds):
filename = cmds[1]
# 以读的方式打开文件,读取文件内容发送给客户端
# 第一步:制作固定长度的报头
header_dic = {
'filename': filename, # 'filename':'1.mp4'
'md5': 'xxdxxx',
'file_size': os.path.getsize(r'%s/%s' % (share_dir, filename))
}
header_json = json.dumps(header_dic)
header_bytes = header_json.encode('utf-8')
# 第二步:先发送报头的长度
conn.send(struct.pack('i', len(header_bytes)))
# 第三步:再发报头
conn.send(header_bytes)
# 第四步:再发送真实的数据
with open('%s/%s' % (share_dir, filename), 'rb') as f:
# conn.send(f.read())
for line in f:
conn.send(line)
def put(conn,cmds):
pass
def run():
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
phone.bind(('127.0.0.1',8912))
phone.listen(5)
print('starting...')
while True: # 链接循环
conn,client_addr=phone.accept()
print(client_addr)
while True: #通信循环
try:
#1、收命令
res=conn.recv(8096) # b'put 1.mp4'
if not res:break #适用于linux操作系统
#2、解析命令,提取相应命令参数
cmds=res.decode('utf-8').split() #['put','xxx.mp4']
if cmds[0] == 'get':
get(conn,cmds)
elif cmds[0] == 'put':
input(conn,cmds)
except ConnectionResetError: #适用于windows操作系统
break
conn.close()
phone.close()
if __name__ == '__main__':
run()
```
## clinet端代码
```
import socket
import struct
import json
download_dir=r'/Users/XXX/client/download'
def get(phone,cmds):
# 以写的方式打开一个新文件,接收服务端发来的文件的内容写入客户的新文件
# 第一步:先收报头的长度
obj = phone.recv(4)
header_size = struct.unpack('i', obj)[0]
# 第二步:再收报头
header_bytes = phone.recv(header_size)
# 第三步:从报头中解析出对真实数据的描述信息
header_json = header_bytes.decode('utf-8')
header_dic = json.loads(header_json)
'''
header_dic={
'filename': filename, #'filename':'1.mp4'
'md5':'xxdxxx',
'file_size': os.path.getsize(filename)
}
'''
print(header_dic)
total_size = header_dic['file_size']
filename = header_dic['filename']
# 第四步:接收真实的数据
with open('%s/%s' % (download_dir, filename), 'wb') as f:
recv_size = 0
while recv_size < total_size:
line = phone.recv(1024) # 1024是一个坑
f.write(line)
recv_size += len(line)
print('总大小:%s 已下载大小:%s' % (total_size, recv_size))
def put(phone,cmds):
pass
def run():
phone=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
phone.connect(('127.0.0.1',8912))
while True:
#1、发命令
inp=input('>>: ').strip() #get a.txt
if not inp:continue
phone.send(inp.encode('utf-8'))
cmds=inp.split() #['get','a.txt']
if cmds[0] == 'get':
get(phone,cmds)
elif cmds[0] == 'put':
put(phone,cmds)
phone.close()
if __name__ == '__main__':
run()
```
- 基础部分
- 基础知识
- 变量
- 数据类型
- 数字与布尔详解
- 列表详解list
- 字符串详解str
- 元组详解tup
- 字典详解dict
- 集合详解set
- 运算符
- 流程控制与循环
- 字符编码
- 编的小程序
- 三级菜单
- 斐波那契数列
- 汉诺塔
- 文件操作
- 函数相关
- 函数基础知识
- 函数进阶知识
- lambda与map-filter-reduce
- 装饰器知识
- 生成器和迭代器
- 琢磨的小技巧
- 通过operator函数将字符串转换回运算符
- 目录规范
- 异常处理
- 常用模块
- 模块和包相关概念
- 绝对导入&相对导入
- pip使用第三方源
- time&datetime模块
- random随机数模块
- os 系统交互模块
- sys系统模块
- shutil复制&打包模块
- json&pickle&shelve模块
- xml序列化模块
- configparser配置模块
- hashlib哈希模块
- subprocess命令模块
- 日志logging模块基础
- 日志logging模块进阶
- 日志重复输出问题
- re正则表达式模块
- struct字节处理模块
- abc抽象类与多态模块
- requests与urllib网络访问模块
- 参数控制模块1-optparse-过时
- 参数控制模块2-argparse
- pymysql数据库模块
- requests网络请求模块
- 面向对象
- 面向对象相关概念
- 类与对象基础操作
- 继承-派生和组合
- 抽象类与接口
- 多态与鸭子类型
- 封装-隐藏与扩展性
- 绑定方法与非绑定方法
- 反射-字符串映射属性
- 类相关内置方法
- 元类自定义及单例模式
- 面向对象的软件开发
- 网络-并发编程
- 网络编程SOCKET
- socket简介和入门
- socket代码实例
- 粘包及粘包解决办法
- 基于UDP协议的socket
- 文件传输程序实战
- socketserver并发模块
- 多进程multiprocessing模块
- 进程理论知识
- 多进程与守护进程
- 锁-信号量-事件
- 队列与生产消费模型
- 进程池Pool
- 多线程threading模块
- 进程理论和GIL锁
- 死锁与递归锁
- 多线程与守护线程
- 定时器-条件-队列
- 线程池与进程池(新方法)
- 协程与IO模型
- 协程理论知识
- gevent与greenlet模块
- 5种网络IO模型
- 非阻塞与多路复用IO实现
- 带着目标学python
- Pycharm基本使用
- 爬虫
- 案例-爬mzitu美女
- 案例-爬小说
- beautifulsoup解析模块
- etree中的xpath解析模块
- 反爬对抗-普通验证码
- 反爬对抗-session登录
- 反爬对抗-代理池
- 爬虫技巧-线程池
- 爬虫对抗-图片懒加载
- selenium浏览器模拟