1. 程式人生 > >小白學習之路,網絡編程(下)

小白學習之路,網絡編程(下)

多人 困難 get err lose imp 出現 popen one

一,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:break
12 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()
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     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搬到博客上,現在慢慢也成了自己有時候類似寫日記的地方了。挺迷茫的,一個啥子都不會的大學生,周圍優秀的人越來越優秀,不過還好有你陪我,你教會了我挺多的,希望我付出的努力以後能給你帶來幸福。

小白學習之路,網絡編程(下)