python学习笔记_week8
一、Socket
当服务端传的东西大于客户端的最大值时怎么办?①改大buffer不行(有上限)②多传几次(用for循环必须要知道循环几次,所以不用for循环,用while)
服务端:
import os
import socket
server=socket.socket()
server.bind(("localhost",9999)) server.listen() while True:
conn,addr=server.accept()
print("new conn:",addr)
while True:
print("等待新指令")
data=conn.recv(700)
if not data :
print("客户端已断开")
break
print("执行指令:",data)
cmd_res=os.popen(data.decode()).read() #接受字符串,执行结果也是字符串
print("before send",len(cmd_res.encode()))
if len(cmd_res)==0:
cmd_res="cmd has no output..."
conn.send(str(len(cmd_res.encode())).encode("utf-8")) #先发大小给客户端
#字符串才能encode,cmd_res要encode 否则因为中文的原因长度会不相等
conn.send(cmd_res.encode("utf-8"))
print("send done")
server.close()
客户端:
import socket
client=socket.socket()
client.connect(("localhost",9999)) while True:
cmd=input(">>:").strip()
if len(cmd) == 0 :
continue
client.send(cmd.encode("utf-8"))
cmd_res_size=client.recv(700) #接收命定结果的长度
print("命令结果:",cmd_res_size)
received_size=0
received_data=b""
while received_size != int(cmd_res_size.decode()):
data=client.recv(700)
received_size+=len(data) #每次收到的有可能小于700,所以必须用len判断
# print(data.decode())
received_data+=data
else:
print("cmd res receive done",received_size)
# cmd_res=client.recv(700)
print(received_data.decode())
client.close()
socket粘包:两次send紧挨着,缓冲区将其打包成一次send,导致出错(用time.sleep()解决太low了,不要用),可以在两次send间插入一次交互,如在服务器端client_ack=conn.recv(700) #wait client to confirm,在客户端client.send("准备好接收了,loser可以发了".encode("utf-8")) PS:windows上粘包现象可能不会显示出来,但Linux一定会。


ftp server:1.读取文件名;2.检测文件是否存在;3.打开文件;4.检测文件大小;5.发送文件大小给客户端;6.等客户端确认;7.开始边读边发数据;8.发送md5;
服务端:
import hashlib
import os
import socket
server=socket.socket()
server.bind(("localhost",9999)) server.listen() while True:
conn,addr=server.accept()
print("new conn:",addr)
while True:
print("等待新指令")
data=conn.recv(700)
if not data :
print("客户端已断开")
break
cmd,filename=data.decode().split()
print(filename)
if os.path.isfile(filename): #判断文件是否存在
f=open(filename,"rb")
m=hashlib.md5()
file_size=os.stat(filename).st_size #文件大小
conn.send(str(file_size).encode()) #send file size
conn.recv(700) #wait for ack
for line in f:
m.update(line)
conn.send(line)
print("file md5",m.hexdigest()) #加上md5速度会慢下来
f.close()
conn.send(m.hexdigest().encode()) #send md5
print("send done")
server.close()
客户端:
import socket
import hashlib
client=socket.socket()
client.connect(("localhost",9999)) while True:
cmd=input(">>:").strip()
if len(cmd) == 0 :
continue
if cmd.startswith("get"):
client.send(cmd.encode())
server_response=client.recv(700)
print("server response",server_response)
client.send(b"ready to recv file")
file_total_size=int(server_response.decode())
received_size=0
filename=cmd.split()[1]
f=open(filename+".new","wb")
m=hashlib.md5()
while received_size < file_total_size:
if file_total_size - received_size > 700:#要收不止一次
size=700
else: #最后一次了,剩多少就只收多少
size=file_total_size-received_size
#上面的判断是为了防止粘包。粘包只可能发生在最后一次
print("last receive:",size)
data=client.recv(size)
received_size+=len(data)
m.update(data)
f.write(data)
#print(file_total_size,received_size)
else:
new_file_md5=m.hexdigest()
print("file recv done",file_total_size,received_size)
f.close()
server_file_md5=client.recv(700)
print("server file md5:",server_file_md5)
print("client file md5:",new_file_md5)
client.close()
二、Socketsever
最主要的作用:并发处理。定义:简化网络任务服务器端的编写(对socket的再封装)
1.socketserver.TCPServer;2.socketserver.UDPServer;3.socketserver.UnixStreamServer;4.socketserver.UnixDatagramServer

创建SocketServer的步骤:
1.你必须自己创建一个请求处理类,并且这个类要继承BaseRequestHandler,并且还要重写父类里的handle()。
2.你必须实例化TCPserver(其他也行),并且传递server ip 和你上面创建的请求处理类给这个TCPserver。
3.server.handle_request() #只处理一个请求(不常用)
server.handle_forever()#处理多个请求,永远执行
调用server_close()来关闭
跟客户端所有的交互都是在handle里完成的
import socketserver class MyTCPHandler(socketserver.BaseRequestHandler):
"""
The request handler class for our server. It is instantiated once per connection to the server, and must
override the handle() method to implement communication to the
client.
""" def handle(self):
while True:
try:
# self.request is the TCP socket connected to the client
self.data = self.request.recv(1024).strip() #每一个客户端的请求过来都会实例化MyTCPHandler
print("{} wrote:".format(self.client_address[0]))
print(self.data)
# if not self.data:#客户端断了
# print(self.client_address,"断开了")
# break
# just send back the same data, but upper-cased
self.request.send(self.data.upper())
except ConnectionResetError as e:
print("err:",e)
break if __name__ == "__main__":
HOST, PORT = "localhost", 9999 # Create the server, binding to localhost on port 9999
server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) #把ip地址和类当做参数传给TCPServer,TCPServer就开始监听
# 和实例化MyTCPHandler,拿handle()与客户端交互 # Activate the server; this will keep running until you
# interrupt the program with Ctrl-C
server.serve_forever()
多并发:每来一个请求,开启一个新线程。
让你的socketserver并发起来, 必须选择使用以下一个多并发的类
class socketserver.ForkingTCPServer
class socketserver.ForkingUDPServer
class socketserver.ThreadingTCPServer
class socketserver.ThreadingUDPServer

ForkingTCPServer 多进程(效果与多线程一样)。(在windows上不能执行,没有fork)
socketserver.BaseServer(server_address, RequestHandlerClass) 主要有以下方法:1.fileno() 返回文件描述符(一般用不到)2.handle_request() 处理单个请求
3.serve_forever(poll_interval=0.5) 每0.5秒检测一下是否有shutdown信号 4.service_actions() 5.shutdown() 6.server_close() 7.address_family 8.RequestHandlerClass 9.server_address 10.socket 11.allow_reuse_address 12.request_queue_size 13.socket_type 14.timeout 15.finish_request()(self.setup(),self.handle(),self.finish())16.get_request() 17.handle_error(request, client_address) 18.handle_timeout() 19.process_request(request, client_address) 20.server_activate() 21.server_bind() 22.verify_request(request, client_address)
作业:开发一个支持多用户在线的FTP程序
要求:
- 用户加密认证
- 允许同时多用户登录
- 每个用户有自己的家目录 ,且只能访问自己的家目录
- 对用户进行磁盘配额,每个用户的可用空间不同
- 允许用户在ftp server上随意切换目录
- 允许用户查看当前目录下文件
- 允许上传和下载文件,保证文件一致性
- 文件传输过程中显示进度条
- 附加功能:支持文件的断点续传

服务器端:
import socketserver
import json,os
class MyTCPHandler(socketserver.BaseRequestHandler):
def put(self,*args):
'''接受客户端文件'''
cmd_dic=args[0]
filename=cmd_dic["filename"]
file_size=cmd_dic["size"]
if os.path.isfile(filename):
f=open(filename+".new","wb")
else:
f=open(filename,"wb")
self.request.send(b"200 ok") #返回客户端请求
receive_size=0
while receive_size<file_size:
data=self.request.recv(1024)
f.write(data)
receive_size+=len(data)
else:
print("file [%s] has uploaded..."%filename)
def handle(self):
while True:
try:
self.data = self.request.recv(1024).strip() #每一个客户端的请求过来都会实例化MyTCPHandler
print("{} wrote:".format(self.client_address[0]))
print(self.data)
cmd_dic=json.loads(self.data.decode())
action=cmd_dic["action"]
if hasattr(self,action):
func=getattr(self,action)
func(cmd_dic)
self.request.send(self.data.upper())
except ConnectionResetError as e:
print("err:",e)
break
if __name__ == "__main__":
HOST, PORT = "localhost", 9999
server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) #把ip地址和类当做参数传给TCPServer,TCPServer就开始监听
server.serve_forever()
客户端:
import socket
import json
import os
class Ftpclient(object):
def __init__(self):
self.client = socket.socket()
def help(self):
msg='''
ls
pwd
cd../..
get filename
put filename'''
print(msg)
def connect(self,ip,port):
self.client.connect((ip, port))
def interactive(self):
#self.authenticate() #用户登录
while True:
cmd=input(">>:")
if len(cmd)==0:continue
cmd_str=cmd.split()[0]#第一个值是指令
if hasattr(self,"cmd_%s"%cmd_str):
func=getattr(self,"cmd_%s"%cmd_str)
func(cmd)
else:
self.help()
def cmd_put(self,*args):
cmd_split=args[0].split()
if len(cmd_split) > 1:
filename=cmd_split[1]
if os.path.isfile(filename):
file_size=os.stat(filename).st_size
# msg_str="%s|%s"%(filename,file_size) #写死了,要考虑长远
msg_dic={
"action":"put",
"filename":filename,
"size":file_size,
"overriden":True
}
self.client.send(json.dumps(msg_dic).encode("utf-8"))
print("send",json.dumps(msg_dic).encode("utf-8"))
#防止粘包,等服务器确认
server_response=self.client.recv(1024)
f=open(filename,"rb")
for line in f:
self.client.send(line)
else:
print("file upload success...")
f.close()
else:
print(filename,"is not exist")
def cmd_get(self):
pass
ftp=Ftpclient()
ftp.connect("localhost",9999)
ftp.interactive()
python学习笔记_week8的更多相关文章
- python学习笔记整理——字典
python学习笔记整理 数据结构--字典 无序的 {键:值} 对集合 用于查询的方法 len(d) Return the number of items in the dictionary d. 返 ...
- VS2013中Python学习笔记[Django Web的第一个网页]
前言 前面我简单介绍了Python的Hello World.看到有人问我搞搞Python的Web,一时兴起,就来试试看. 第一篇 VS2013中Python学习笔记[环境搭建] 简单介绍Python环 ...
- python学习笔记之module && package
个人总结: import module,module就是文件名,导入那个python文件 import package,package就是一个文件夹,导入的文件夹下有一个__init__.py的文件, ...
- python学习笔记(六)文件夹遍历,异常处理
python学习笔记(六) 文件夹遍历 1.递归遍历 import os allfile = [] def dirList(path): filelist = os.listdir(path) for ...
- python学习笔记--Django入门四 管理站点--二
接上一节 python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...
- python学习笔记--Django入门0 安装dangjo
经过这几天的折腾,经历了Django的各种报错,翻译的内容虽然不错,但是与实际的版本有差别,会出现各种奇葩的错误.现在终于找到了解决方法:查看英文原版内容:http://djangobook.com/ ...
- python学习笔记(一)元组,序列,字典
python学习笔记(一)元组,序列,字典
- Pythoner | 你像从前一样的Python学习笔记
Pythoner | 你像从前一样的Python学习笔记 Pythoner
- OpenCV之Python学习笔记
OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...
随机推荐
- TStrings (TStringList)很有功能
用 TStrings的Object 保存类的方式,来保存除了Items以外的值. 今天才发现,原来,TStrings下,还有 Items,Values,Items.Names,Items.Values ...
- influxDB硬件配置指南
原地址:https://docs.influxdata.com/influxdb/v1.6/guides/hardware_sizing/ 警告!此页面记录了不再积极开发的InfluxDB的早期版本. ...
- CI 数据库操作总结
最简单示例 $query = $this->db->query("YOUR QUERY"); foreach ($query->result() as $row) ...
- intellij idea 设置 Error 提示颜色修改
File--->Settings --->Editor --->ColorScheme--->General --->Errors and Warning--->E ...
- 黄聪:bootstrap的模态框modal插件在苹果iOS Safari下光标偏离问题解决方案
一行CSS代码搞定: body.modal-open { position: fixed; width: 100%; }
- DS哈希查找--线性探测再散列
题目描述 定义哈希函数为H(key) = key%11.输入表长(大于.等于11),输入关键字集合,用线性探测再散列构建哈希表,并查找给定关键字. --程序要求-- 若使用C++只能include一个 ...
- svn项目清除svn链接信息
如果copy的项目原来有svn连接信息,测试新技术新方案时可能会有隐患,不小心上传svn很造成很多麻烦. 这时先删除svn连接是比较好的选择. 删除svn的方法是删除项目根目录下的.svn文件夹.这个 ...
- 【占位符替换】替换String中的占位符标志位{placeholder}
概述 占位符替换, 占位符表示为:{placeholder}; 示例:替换如下{xxx}占位符中的内容 "名字:{name},年龄:{age},学校:{school}" 提供了两种 ...
- vue-router配合vue-cli的实例
前面在说到vue-router的时候,都是用最简单的方式说明用法的,但是在实际项目中可能会有所出入,所以,今天就结合vue脚手架来展示项目中的vue-router的用法. 创建项目 首先需要使用脚手架 ...
- mysql查询优化之三:查询优化器提示(hint)
目录: <MySQL中的两种临时表>--强制使用临时表 SQL_BUFFER_RESULT <MySQL 多表关联更新及删除> <mysql查询优化之三:查询优化器提示( ...