python学习笔记_week8

一、Socket

当服务端传的东西大于客户端的最大值时怎么办?①改大buffer不行(有上限)②多传几次(用for循环必须要知道循环几次,所以不用for循环,用while)

服务端:

 1 import os
 2 import socket
 3 server=socket.socket()
 4 server.bind(("localhost",9999))
 5 
 6 server.listen()
 7 
 8 while True:
 9     conn,addr=server.accept()
10     print("new conn:",addr)
11     while True:
12         print("等待新指令")
13         data=conn.recv(700)
14         if not data :
15             print("客户端已断开")
16             break
17         print("执行指令:",data)
18         cmd_res=os.popen(data.decode()).read() #接受字符串,执行结果也是字符串
19         print("before send",len(cmd_res.encode()))
20         if len(cmd_res)==0:
21             cmd_res="cmd has no output..."
22         conn.send(str(len(cmd_res.encode())).encode("utf-8")) #先发大小给客户端
23         #字符串才能encode,cmd_res要encode 否则因为中文的原因长度会不相等
24         conn.send(cmd_res.encode("utf-8"))
25         print("send done")
26 server.close()
View Code

客户端:

 1 import socket
 2 client=socket.socket()
 3 client.connect(("localhost",9999))
 4 
 5 while True:
 6     cmd=input(">>:").strip()
 7     if len(cmd) == 0 :
 8         continue
 9     client.send(cmd.encode("utf-8"))
10     cmd_res_size=client.recv(700) #接收命定结果的长度
11     print("命令结果:",cmd_res_size)
12     received_size=0
13     received_data=b""
14     while received_size != int(cmd_res_size.decode()):
15         data=client.recv(700)
16         received_size+=len(data) #每次收到的有可能小于700,所以必须用len判断
17         # print(data.decode())
18         received_data+=data
19     else:
20         print("cmd res receive done",received_size)
21     # cmd_res=client.recv(700)
22         print(received_data.decode())
23 client.close()
View Code

 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;

服务端:

 1 import hashlib
 2 import os
 3 import socket
 4 server=socket.socket()
 5 server.bind(("localhost",9999))
 6 
 7 server.listen()
 8 
 9 while True:
10     conn,addr=server.accept()
11     print("new conn:",addr)
12     while True:
13         print("等待新指令")
14         data=conn.recv(700)
15         if not data :
16             print("客户端已断开")
17             break
18         cmd,filename=data.decode().split()
19         print(filename)
20         if os.path.isfile(filename): #判断文件是否存在
21             f=open(filename,"rb")
22             m=hashlib.md5()
23             file_size=os.stat(filename).st_size #文件大小
24             conn.send(str(file_size).encode()) #send file size
25             conn.recv(700) #wait for ack
26             for line in f:
27                 m.update(line)
28                 conn.send(line)
29             print("file md5",m.hexdigest()) #加上md5速度会慢下来
30             f.close()
31             conn.send(m.hexdigest().encode()) #send md5
32         print("send done")
33 server.close()
View Code

客户端:

 1 import socket
 2 import hashlib
 3 client=socket.socket()
 4 client.connect(("localhost",9999))
 5 
 6 while True:
 7     cmd=input(">>:").strip()
 8     if len(cmd) == 0 :
 9         continue
10     if cmd.startswith("get"):
11         client.send(cmd.encode())
12         server_response=client.recv(700)
13         print("server response",server_response)
14         client.send(b"ready to recv file")
15         file_total_size=int(server_response.decode())
16         received_size=0
17         filename=cmd.split()[1]
18         f=open(filename+".new","wb")
19         m=hashlib.md5()
20         while received_size < file_total_size:
21             if file_total_size - received_size > 700:#要收不止一次
22                 size=700
23             else: #最后一次了,剩多少就只收多少
24                 size=file_total_size-received_size
25 #上面的判断是为了防止粘包。粘包只可能发生在最后一次
26                 print("last receive:",size)
27             data=client.recv(size)
28             received_size+=len(data)
29             m.update(data)
30             f.write(data)
31             #print(file_total_size,received_size)
32         else:
33             new_file_md5=m.hexdigest()
34             print("file recv done",file_total_size,received_size)
35             f.close()
36         server_file_md5=client.recv(700)
37         print("server file md5:",server_file_md5)
38         print("client file md5:",new_file_md5)
39 client.close()
View Code

 二、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里完成的

 1 import socketserver
 2 
 3 class MyTCPHandler(socketserver.BaseRequestHandler):
 4     """
 5     The request handler class for our server.
 6 
 7     It is instantiated once per connection to the server, and must
 8     override the handle() method to implement communication to the
 9     client.
10     """
11 
12     def handle(self):
13         while True:
14             try:
15                 # self.request is the TCP socket connected to the client
16                 self.data = self.request.recv(1024).strip() #每一个客户端的请求过来都会实例化MyTCPHandler
17                 print("{} wrote:".format(self.client_address[0]))
18                 print(self.data)
19                 # if not self.data:#客户端断了
20                 #     print(self.client_address,"断开了")
21                 #     break
22                 # just send back the same data, but upper-cased
23                 self.request.send(self.data.upper())
24             except ConnectionResetError as e:
25                 print("err:",e)
26                 break
27 
28 if __name__ == "__main__":
29     HOST, PORT = "localhost", 9999
30 
31     # Create the server, binding to localhost on port 9999
32     server = socketserver.TCPServer((HOST, PORT), MyTCPHandler) #把ip地址和类当做参数传给TCPServer,TCPServer就开始监听
33     # 和实例化MyTCPHandler,拿handle()与客户端交互
34 
35     # Activate the server; this will keep running until you
36     # interrupt the program with Ctrl-C
37     server.serve_forever()
View Code

多并发:每来一个请求,开启一个新线程。

让你的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. 附加功能:支持文件的断点续传

服务器端:

 1 import socketserver
 2 import json,os
 3 class MyTCPHandler(socketserver.BaseRequestHandler):
 4     def put(self,*args):
 5         '''接受客户端文件'''
 6         cmd_dic=args[0]
 7         filename=cmd_dic["filename"]
 8         file_size=cmd_dic["size"]
 9         if os.path.isfile(filename):
10             f=open(filename+".new","wb")
11         else:
12             f=open(filename,"wb")
13         self.request.send(b"200 ok") #返回客户端请求
14         receive_size=0
15         while receive_size<file_size:
16             data=self.request.recv(1024)
17             f.write(data)
18             receive_size+=len(data)
19         else:
20             print("file [%s] has uploaded..."%filename)
21     def handle(self):
22         while True:
23             try:
24                 self.data = self.request.recv(1024).strip() #每一个客户端的请求过来都会实例化MyTCPHandler
25                 print("{} wrote:".format(self.client_address[0]))
26                 print(self.data)
27                 cmd_dic=json.loads(self.data.decode())
28                 action=cmd_dic["action"]
29                 if hasattr(self,action):
30                     func=getattr(self,action)
31                     func(cmd_dic)
32                 self.request.send(self.data.upper())
33             except ConnectionResetError as e:
34                 print("err:",e)
35                 break
36 if __name__ == "__main__":
37     HOST, PORT = "localhost", 9999
38     server = socketserver.ThreadingTCPServer((HOST, PORT), MyTCPHandler) #把ip地址和类当做参数传给TCPServer,TCPServer就开始监听
39     server.serve_forever()
View Code

客户端:

 1 import socket
 2 import json
 3 import os
 4 class Ftpclient(object):
 5     def __init__(self):
 6         self.client = socket.socket()
 7     def help(self):
 8         msg='''
 9         ls
10         pwd
11         cd../..
12         get filename
13         put filename'''
14         print(msg)
15     def connect(self,ip,port):
16         self.client.connect((ip, port))
17     def interactive(self):
18         #self.authenticate() #用户登录
19         while True:
20             cmd=input(">>:")
21             if len(cmd)==0:continue
22             cmd_str=cmd.split()[0]#第一个值是指令
23             if hasattr(self,"cmd_%s"%cmd_str):
24                 func=getattr(self,"cmd_%s"%cmd_str)
25                 func(cmd)
26             else:
27                 self.help()
28     def cmd_put(self,*args):
29         cmd_split=args[0].split()
30         if len(cmd_split) > 1:
31             filename=cmd_split[1]
32             if os.path.isfile(filename):
33                 file_size=os.stat(filename).st_size
34                 # msg_str="%s|%s"%(filename,file_size) #写死了,要考虑长远
35                 msg_dic={
36                     "action":"put",
37                     "filename":filename,
38                     "size":file_size,
39                     "overriden":True
40                 }
41                 self.client.send(json.dumps(msg_dic).encode("utf-8"))
42                 print("send",json.dumps(msg_dic).encode("utf-8"))
43                 #防止粘包,等服务器确认
44                 server_response=self.client.recv(1024)
45                 f=open(filename,"rb")
46                 for line in f:
47                     self.client.send(line)
48                 else:
49                     print("file upload success...")
50                     f.close()
51             else:
52                 print(filename,"is not exist")
53     def cmd_get(self):
54         pass
55 ftp=Ftpclient()
56 ftp.connect("localhost",9999)
57 ftp.interactive()
View Code

 

posted on 2017-11-03 19:58  我很好u 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/jyh-py-blog/p/7780246.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值