小白學習之路,網絡編程(下)
一,socket進階
在前面的博客中講到了一些基本的計算機網絡知識,有一點也是為我在要考傳輸與交換看到一個題,然後就看到說ARP屬於網絡層,因為ARP協議跟網絡相關,但是我前面的博客說的是ARP協議屬於數據鏈路層。當時我就呆了,不會講錯了吧,後來查了一下,原來都是可以的,ARP協議有的人說在網絡層也行,在數據鏈路層也行。當然這只是一個小插曲。昨天在講到socket的幾種情況還沒解決,這篇文章就跟大家解決。大概有幾個問題,一個是每次只能接受一定數據大小的數據,如果數據太大怎麽辦?還有提到的粘包的問題,還有一個就是只能同時一個客戶端連上服務器,其他服務器都要等著。
1,先用socket實現一個簡單的ssh
ssh服務端
1 import socket,os 2 server=socket.socket() 3 server.bind((‘127.0.0.1‘,1314)) 4 server.listen() 5 while True: 6 conn,addr=server.accept() 7 try: 8 while True: 9 data=conn.recv(1024) 10 print(‘客戶端發來的命令是:‘,data.decode()) 11 if not data:breakView Code12 if len(data)==0: 13 print(‘命令為空‘) 14 send_data=os.popen(data.decode()).read()#執行命令,並讀出結果 15 conn.send(send_data.encode()) 16 except ConnectionResetError as e: 17 print(‘一個客戶端斷開連接‘) 18 conn.close() 19 server.colse()
ssh客戶端
1 import socket 2 client=socket.socket() 3 client.connect((‘127.0.0.1‘,1314)) 4 while True: 5 data=input(‘>>>‘) 6 if len(data)==0:continue 7 client.send(data.encode()) 8 recv_data=client.recv(1024) 9 print(recv_data.decode()) 10 client.close()View Code
寫好了,忍不住要開始裝逼了,於是你在客戶端輸入了一個dir運行結果如下
>>>dir 驅動器 E 中的卷是 新加卷 卷的序列號是 CA7D-FFB5 E:\zzq_python\博客 的目錄 2018/06/29 15:49 <DIR> . 2018/06/29 15:49 <DIR> .. 2018/06/24 22:36 1,709 calculator.py 2018/06/26 09:34 1,048 deal_error.py 2018/06/28 18:08 349 socket_client.py 2018/06/28 18:06 453 socket_server.py 2018/06/29 15:47 253 ssh_client.py 2018/06/29 15:49 613 ssh_server.py 2018/06/26 16:50 1,508 單例模式.py 2018/06/26 10:22 454 接口類.py 8 個文件 6,387 字節 2 個目錄 60,092,284,928 可用字節
但是想了想不得行,這個還不夠啊,於是你查了一些你電腦的ip地址,運行結果就不貼出來了。你會驚奇的發現,怎麽回事啊。為什麽沒有顯示完呢。仔細想了想,出現前面提到的問題了,每次接收只能接收固定長度的數據,但是超出了只有在下一次接收的時候接收了,那肯定是不行的啊,這種情況,那也太low了吧。於是為了解決這種問題,我們可以先發一個文件的長度,然後客戶端接收到以後,根據接收的文件長度跟實際長度比較,知道收完為止。emmm,帶著這種想法,我們就來試試實現吧。
2,升級版ssh
ssh服務端
1 import socket,os 2 server=socket.socket() 3 server.bind((‘127.0.0.1‘,1314)) 4 server.listen() 5 while True: 6 conn,addr=server.accept() 7 try: 8 while True: 9 data=conn.recv(1024) 10 print(‘客戶端發來的命令是:‘,data.decode()) 11 if not data:break 12 if len(data)==0: 13 print(‘命令為空‘) 14 send_data=os.popen(data.decode()).read()#執行命令,並讀出結果 15 data_len=len(send_data.encode()) 16 print(‘發送的數據總長度:‘,data_len) 17 conn.send(str(data_len).encode()) 18 print(conn.recv(1024).decode()) 19 conn.send(send_data.encode()) 20 except ConnectionResetError as e: 21 print(‘一個客戶端斷開連接‘) 22 conn.close() 23 server.colse()View Code
ssh客戶端
1 import socket 2 client=socket.socket() 3 client.connect((‘127.0.0.1‘,1314)) 4 while True: 5 data=input(‘>>>‘) 6 if len(data)==0:continue 7 client.send(data.encode()) 8 data_len=client.recv(1024).decode() 9 client.send(‘接收到數據長度了‘.encode()) 10 get_len=0#設置最開始長度為0 11 get_data=b‘‘ 12 while get_len<int(data_len): 13 data=client.recv(1024)#接收的數據 14 get_len+=len(data)#接收的長度 15 get_data+=data 16 print(‘數據長度為:‘,data_len,get_data.decode()) 17 client.close()View Code
當然有的人會對這個代碼感到疑惑,其中為什麽在跟客戶端發送完數據長度以後,不直接發送數據內容,中間要接收客戶端發來的接收數據長度成功,很多人會覺得這是累贅,但是如果你連續兩次發送,這種情況就有可能會出現粘包現象,為了解決這個問題,所以在中途增加了一個接收客戶端的信息。講到這裏就解決了兩個問題了,一個數據過長,一個粘包的問題,還有一個問題就是不能存在多客戶端同時跟服務端交互的問題。
3,實現文件傳輸
在前面的一個ssh做基礎的情況下,我們是不是也能跟ftp一樣傳文件這些呢,當然可以肯定的告訴你,可以傳文件的,而且在後面的學習完成以後,你還能自己寫一個ftp實現上傳下載文件的功能。先做一個簡單的文件傳輸功能吧。
服務端(server)
1 import socket,os 2 server=socket.socket() 3 server.bind((‘127.0.0.1‘,1314)) 4 server.listen() 5 while True: 6 conn,addr=server.accept() 7 print(‘連接成功!‘) 8 try: 9 while True: 10 file_name=conn.recv(1024).decode() 11 if not file_name: break 12 if os.path.isfile(file_name):#判斷文件是否存在 13 file_len=os.stat(file_name).st_size#獲取文件大小 14 conn.send(str(file_len).encode()) 15 conn.recv(1024) 16 with open(file_name,‘rb‘) as f: 17 for i in f: 18 conn.send(i) 19 print(‘文件發送完成‘) 20 else: 21 print(‘文件不存在‘) 22 except ConnectionResetError: 23 print(‘一個客戶端斷開‘) 24 finally: 25 conn.close() 26 server.close()View Code
客戶端(client)
1 import socket 2 client=socket.socket() 3 client.connect((‘127.0.0.1‘,1314)) 4 while True: 5 file_name=input(">>>") 6 if len(file_name)==0:continue 7 client.send(file_name.encode()) 8 file_len=client.recv(1024).decode() 9 client.send(‘接收數據長度成功‘.encode()) 10 get_len=0 11 f=open(file_name,‘wb‘) 12 while get_len<float(file_len): 13 data=client.recv(1024) 14 get_len+=len(data) 15 f.write(data) 16 print(‘已經完成‘,get_len,‘/‘,file_len) 17 print(‘文件傳輸完成‘) 18 f.close() 19 client.close()View Code
基本socket的用法就講完了,當然在使用文件傳輸的時候,最好是用前面學習的hashlib模塊進行文件內容的加密,這裏就不寫了,感興趣可以試著寫一寫,在學習文件傳輸以後,就可以寫一個簡單的ftp了。能夠實現文件的上傳和下載了,上傳就是跟下載相反。不過還是不能實現多個客戶端同時與服務端交互。下面的這個socketserver就很好的解決了這個問題。
二,socketserver用法
前面都是為最後面的裝逼做鋪墊的,沒錯的,下面即將進入的是我們今天的裝逼操作了,socketserver。
當然這裏我們也只是寫簡單的用法,其實用法跟socket用法是差不多的,所以只給了簡單的使用方法
服務端(server)
1 import socketserver 2 class MyServer(socketserver.BaseRequestHandler): 3 def handle(self):#裏面是跟客戶端交互的全過程 4 while True: 5 try: 6 data=self.request.recv(1024) #self.request相當於socket裏面的conn 7 print(‘收到來自客戶端%s的消息:%s‘ %(self.request,data.decode())) 8 self.request.send(data.upper()) 9 except ConnectionResetError as e: 10 print(‘error:‘,e) 11 break 12 if __name__ == ‘__main__‘: 13 #創建一個服務,綁定ip跟端口 14 server=socketserver.ThreadingTCPServer((‘127.0.0.1‘,1314),MyServer) 15 server.serve_forever()#服務一直開啟View Code
客戶端(client)
1 import socket 2 client=socket.socket() 3 client.connect((‘127.0.0.1‘,1314)) 4 while True: 5 data=input(‘>>>‘) 6 client.send(data.encode()) 7 get_data=client.recv(124) 8 print(get_data.decode()) 9 client.close()View Code
這裏客戶端還是使用的socket的方法,多連接只是相當於服務端來說的。
基本已經學完了網絡編程,也能自己實現一個完整的ftp了,雖然有點困難,但是還是推薦自己實現一個,可以加強對代碼的熟悉,而且還能練習到前面學習的東西。馬上期末了,好多作業要做,還要為期末考試做準備,還要準備畢業設計,還要準備找實習工作。哎,感覺有點難受,最近煩心事也是挺多的。寫博客,最開始為了回顧以前學過的知識,把以前自己做的學習筆記從word搬到博客上,現在慢慢也成了自己有時候類似寫日記的地方了。挺迷茫的,一個啥子都不會的大學生,周圍優秀的人越來越優秀,不過還好有你陪我,你教會了我挺多的,希望我付出的努力以後能給你帶來幸福。
小白學習之路,網絡編程(下)