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做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...
随机推荐
- python 中的 metaclass
最遇到一个问题. class Meta(type): pass class M1(Meta): pass class M2(metaclass=M1): pass class Test(M2,meta ...
- C语言中sizeof与strlen的区别
1.sizeof sizeof为编译时期被替换,不会等到程序运行再来判断,所以sizeof返回的是数组的总字节数 #include<stdio.h> int main() { ]={'a' ...
- Oracle 官方文档地址
官方文档地址: https://docs.oracle.com/cd/E11882_01/index.htm
- 在 Vue 项目中引入 tinymce 富文本编辑器
项目中原本使用的富文本编辑器是 wangEditor,这是一个很轻量.简洁编辑器 但是公司的业务升级,想要一个功能更全面的编辑器,我找了好久,目前常见的编辑器有这些: UEditor:百度前端的开源项 ...
- Vue.js系列之项目结构说明
转:https://www.jb51.net/article/111658.htm 前言 在上一篇项目搭建文章中,我们已经下载安装了node环境以及vue-cli,并且已经成功构建了一个vue-cli ...
- Course List for Student
题目描述 Zhejiang University has 40000 students and provides 2500 courses. Now given the student name li ...
- postgresql定位分析消耗CPU高的SQL语句
第一步:使用TOP命令查看占用CPU高的postgresql进程,并获取该进程的ID号,如图该id号为3640 第二步:切换到postgres用户,并且psql连接到数据库,执行如下查询语句 SELE ...
- tf.while_loop
tf.while_loop(cond, body, loop_vars, shape_invariants=None, parallel_iterations=10, back_prop=True, ...
- tf.nn.dropout
tf.nn.dropout(x, keep_prob, noise_shape=None, seed=None, name=None) 此函数是为了防止在训练中过拟合的操作,将训练输出按一定规则进行变 ...
- Delphi根据方法名调用方法
type TForm1 = class(TForm) public published procedure DoJsCall(str:string); ...