天天看點

python學習筆記_week8

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一定會。

python學習筆記_week8
python學習筆記_week8

 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

python學習筆記_week8

建立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

python學習筆記_week8

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程式

要求:

  1. 使用者加密認證
  2. 允許同時多使用者登入
  3. 每個使用者有自己的家目錄 ,且隻能通路自己的家目錄
  4. 對使用者進行磁盤配額,每個使用者的可用空間不同
  5. 允許使用者在ftp server上随意切換目錄
  6. 允許使用者檢視目前目錄下檔案
  7. 允許上傳和下載下傳檔案,保證檔案一緻性
  8. 檔案傳輸過程中顯示進度條
  9. 附加功能:支援檔案的斷點續傳
python學習筆記_week8

伺服器端:

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