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做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...
随机推荐
- JavaScript之WebSocket技术详解
概述 HTTP协议是一种无状态协议,服务器端本身不具有识别客户端的能力,必须借助外部机制,比如session和cookie,才能与特定客户端保持对话.这多多少少带来一些不便,尤其在服务器端与客户端需要 ...
- ThinkPHP 3.1.2 视图 MVC-V -5
一.模板的使用 (重点) a.规则 模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和模块名同名的文件夹[Index]/和方法名同名的文件[index].html(.tpl) ...
- 纯css3实现文字间歇滚动效果
场景: 假设有4条数据或者标题,视口中只显示两条,采用每次向上滚动一条数据来展示所有的数据.效果如图: 用JavaScript也很容易实现,但是需要操作DOM,可以参考这篇博客.考虑到项目中经常使用V ...
- 黄聪:bootstrap的模态框modal插件在苹果iOS Safari下光标偏离问题解决方案
一行CSS代码搞定: body.modal-open { position: fixed; width: 100%; }
- C++11--20分钟了解C++11 (下)
20分钟了解C++11 9 override关键字 (虚函数使用) * * 避免在派生类中意外地生成新函数 */ // C++ 03 class Dog { virtual void A(int); ...
- nump库的简单函数介绍
1:ones函数(百度知道) ones()函数用以创建指定形状和类型的数组,默认情况下返回的类型是float64.但是,如果使用ones()函数时指定了数据类型,那么返回的就是该类型. 参考NumPy ...
- bzoj4948: World Final2017 A
求简单多边形内的最长线段长度 显然存在一组最优解,使其所在直线经过多边形的两个端点,枚举这两个端点,求出直线和多边形的有效交点,从而得出直线有哪些部分在多边形内(含边界). 由于多边形的一些边可能与直 ...
- P2837晚餐队列安排
传送 特写此篇,纪念不用dp做dp题 洛谷说这是个dp,但我不信(其实就是不会dp),因此我们考虑用另一种思路.修改后的队列每一个 数a[i]一定满足a[i]<=a[i+1],那修改后的顺序就是 ...
- 解决python中路径中包含中文无法找到文件的问题
a="C:\Users\Dell\Desktop\ATOU\公共测试用例" (带中文的路径) a=a.decode("utf-8").encode(" ...
- [转] 关于 Ceph PG
本系列文章会深入研究 Ceph 以及 Ceph 和 OpenStack 的集成: (1)安装和部署 (2)Ceph RBD 接口和工具 (3)Ceph 物理和逻辑结构 (4)Ceph 的基础数据结构 ...