一、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_addressRequestHandlerClass) 主要有以下方法: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程序

要求:

  1. 用户加密认证
  2. 允许同时多用户登录
  3. 每个用户有自己的家目录 ,且只能访问自己的家目录
  4. 对用户进行磁盘配额,每个用户的可用空间不同
  5. 允许用户在ftp server上随意切换目录
  6. 允许用户查看当前目录下文件
  7. 允许上传和下载文件,保证文件一致性
  8. 文件传输过程中显示进度条
  9. 附加功能:支持文件的断点续传

服务器端:

 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的更多相关文章

  1. python学习笔记整理——字典

    python学习笔记整理 数据结构--字典 无序的 {键:值} 对集合 用于查询的方法 len(d) Return the number of items in the dictionary d. 返 ...

  2. VS2013中Python学习笔记[Django Web的第一个网页]

    前言 前面我简单介绍了Python的Hello World.看到有人问我搞搞Python的Web,一时兴起,就来试试看. 第一篇 VS2013中Python学习笔记[环境搭建] 简单介绍Python环 ...

  3. python学习笔记之module && package

    个人总结: import module,module就是文件名,导入那个python文件 import package,package就是一个文件夹,导入的文件夹下有一个__init__.py的文件, ...

  4. python学习笔记(六)文件夹遍历,异常处理

    python学习笔记(六) 文件夹遍历 1.递归遍历 import os allfile = [] def dirList(path): filelist = os.listdir(path) for ...

  5. python学习笔记--Django入门四 管理站点--二

    接上一节  python学习笔记--Django入门四 管理站点 设置字段可选 编辑Book模块在email字段上加上blank=True,指定email字段为可选,代码如下: class Autho ...

  6. python学习笔记--Django入门0 安装dangjo

    经过这几天的折腾,经历了Django的各种报错,翻译的内容虽然不错,但是与实际的版本有差别,会出现各种奇葩的错误.现在终于找到了解决方法:查看英文原版内容:http://djangobook.com/ ...

  7. python学习笔记(一)元组,序列,字典

    python学习笔记(一)元组,序列,字典

  8. Pythoner | 你像从前一样的Python学习笔记

    Pythoner | 你像从前一样的Python学习笔记 Pythoner

  9. OpenCV之Python学习笔记

    OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...

随机推荐

  1. windows的消息传递--消息盒子

    例如对windows发消息让文本选中.     SendMessage(Text1.hwnd,EM_GETSEL,0,-1 ); EC_LEFTMARGIN(&H1) EC_USEFONTIN ...

  2. linux 如何运行rpm

    rpm -ivh linuxqq-v1.0.2-beta1.i386.rpm

  3. jquery 中prop和 attr

    prop就是给html中元素固有的属性赋值 而attr是给元素定义新的属性值.

  4. DS图遍历--深度优先搜索

    DS图遍历--深度优先搜索 题目描述 给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始 注意:图n个顶点编号从0到n-1 代码框架如下: 输入 第一行输入t,表示有t个测试实例 第二行输入n, ...

  5. 【Graphite学习】系列学习文章-【转】

    Graphite 系列 #2:Carbon 和 Whisper GRAPHITE SERIES #1: PROVISION HARDWARE GRAPHITE SERIES #2: CARBON &a ...

  6. 关于socket阻塞与非阻塞情况下的recv、send、read、write返回值---部分内容可能不确切,待讨论

    1.阻塞模式与非阻塞模式下recv的返回值各代表什么意思?有没有区别?(就我目前了解阻塞与非阻塞recv返回值没有区分,都是 <0:出错,=0:连接关闭,>0接收到数据大小,特别:返回值  ...

  7. Hadoop概念学习系列之Java调用Shell命令和脚本,致力于hadoop/spark集群(三十六)

    前言 说明的是,本博文,是在以下的博文基础上,立足于它们,致力于我的大数据领域! http://kongcodecenter.iteye.com/blog/1231177 http://blog.cs ...

  8. 史上最全Spring面试71题与答案

    1.什么是spring? Spring是个java企业级应用的开源开发框架.Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用.Spring框架目标是简化Java企业 ...

  9. MATLAB的一些小技巧

    写论文要将图片保存为tiff格式,还要求dpi,还要标注,真是麻烦,下面的命令是最方便的程序化处理方式了 MATLAB text标注后 保存为 tiff 图片,图片到边框间无空白 clear all; ...

  10. RabbitMQ用户角色及权限控制(转)

    转载至:https://blog.csdn.net/awhip9/article/details/72123257 2017年05月15日 10:39:26 awhip9 阅读数:3538   ### ...